微服务OpenFeign源码分析

深入理解OpenFeign源码,可以深入理解接口调用转为HTTP请求、实现负载均衡工作机制,便于根据业务定制扩展功能,或者快速定位请求问题根源。另一方面,可以理解动态代理优秀设计模式,有助于提升开发者架构设计与编程能力。

01 自动装配

OpenFeign依赖spring-cloud-openfeign-core.jar配置默认行为,借助spring.factories文件实现配置发现和解析。

properties 复制代码
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration,\
org.springframework.cloud.openfeign.hateoas.FeignHalAutoConfiguration,\
org.springframework.cloud.openfeign.FeignAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration

1.1 客户端配置

FeignAutoConfiguration用于配置Feign默认组件,默认提供Feign、FeignContext和HTTP客户端配置。

java 复制代码
@EnableConfigurationProperties({FeignClientProperties.class, FeignHttpClientProperties.class })
@Import(DefaultGzipDecoderConfiguration.class)
public class FeignAutoConfiguration {
    @Autowired(required = false)
    private List<FeignClientSpecification> configurations = new ArrayList<>();
    
    @Bean
    public FeignContext feignContext() {
        FeignContext context = new FeignContext();
        context.setConfigurations(this.configurations);
        return context;
    }
    
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
    protected static class DefaultFeignTargeterConfiguration {
        @Bean
        @ConditionalOnMissingBean
        public Targeter feignTargeter() {
            return new DefaultTargeter();
        }
    }
    
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(ApacheHttpClient.class)
    @ConditionalOnMissingBean(CloseableHttpClient.class)
    @ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
    @ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
    protected static class HttpClientFeignConfiguration {
        @Autowired(required = false)
        private RegistryBuilder registryBuilder;

        private CloseableHttpClient httpClient;

        @Bean
        @ConditionalOnMissingBean(HttpClientConnectionManager.class)
        public HttpClientConnectionManager connectionManager(
            ApacheHttpClientConnectionManagerFactory connectionManagerFactory,
            FeignHttpClientProperties httpClientProperties) {
            final HttpClientConnectionManager connectionManager = connectionManagerFactory
                    .newConnectionManager(httpClientProperties.isDisableSslValidation(),
                            httpClientProperties.getMaxConnections(),
                            httpClientProperties.getMaxConnectionsPerRoute(),
                            httpClientProperties.getTimeToLive(),
                            httpClientProperties.getTimeToLiveUnit(),
                            this.registryBuilder);
            this.connectionManagerTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    connectionManager.closeExpiredConnections();
                }
            }, 30000, httpClientProperties.getConnectionTimerRepeat());
            return connectionManager;
        }

        @Bean
        public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory,
                HttpClientConnectionManager httpClientConnectionManager,
                FeignHttpClientProperties httpClientProperties) {
            RequestConfig defaultRequestConfig = RequestConfig.custom()
                    .setConnectTimeout(httpClientProperties.getConnectionTimeout())
                    .setRedirectsEnabled(httpClientProperties.isFollowRedirects())
                    .build();
            this.httpClient = httpClientFactory.createBuilder()
                    .setConnectionManager(httpClientConnectionManager)
                    .setDefaultRequestConfig(defaultRequestConfig).build();
            return this.httpClient;
        }

        @Bean
        @ConditionalOnMissingBean(Client.class)
        public Client feignClient(HttpClient httpClient) {
            return new ApacheHttpClient(httpClient);
        }
    }
}

1.2 Feign上下文

FeignContext全局默认类为FeignClientsConfiguration,解析过程与Ribbon、LoadBalancer相同。

java 复制代码
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
    public FeignContext() {
        super(FeignClientsConfiguration.class, "feign", "feign.client.name");
    }

    @Nullable
    public <T> T getInstanceWithoutAncestors(String name, Class<T> type) {
        try {
            return BeanFactoryUtils.beanOfType(getContext(name), type);
        }
        catch (BeansException ex) {
            return null;
        }
    }

    @Nullable
    public <T> Map<String, T> getInstancesWithoutAncestors(String name, Class<T> type) {
        return getContext(name).getBeansOfType(type);
    }
}

1.3 全局默认配置

Feign全局默认配置类为FeignClientsConfiguration,提供编码器(Encoder)、解码器(Decoder)、锲约(Contract)、客户端代理创建(Targeter)等配置支持。

java 复制代码
@Configuration(proxyBeanMethods = false)
public class FeignClientsConfiguration {
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;
    @Autowired(required = false)
    private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
    @Autowired(required = false)
    private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
    @Autowired(required = false)
    private Logger logger;
    @Autowired(required = false)
    private SpringDataWebProperties springDataWebProperties;

    @Bean
    @ConditionalOnMissingBean
    public Decoder feignDecoder() {
        return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
    }
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
    public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        return springEncoder(formWriterProvider);
    }
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
    public Encoder feignEncoderPageable(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        PageableSpringEncoder encoder = new PageableSpringEncoder(springEncoder(formWriterProvider));
        if (springDataWebProperties != null) {
            encoder.setPageParameter(springDataWebProperties.getPageable().getPageParameter());
            encoder.setSizeParameter(springDataWebProperties.getPageable().getSizeParameter());
            encoder.setSortParameter(springDataWebProperties.getSort().getSortParameter());
        }
        return encoder;
    }
    @Bean
    @ConditionalOnMissingBean
    public Contract feignContract(ConversionService feignConversionService) {
        return new SpringMvcContract(this.parameterProcessors, feignConversionService);
    }
    @Bean
    public FormattingConversionService feignConversionService() {
        FormattingConversionService conversionService = new DefaultFormattingConversionService();
        for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) {
            feignFormatterRegistrar.registerFormatters(conversionService);
        }
        return conversionService;
    }
    @Bean
    @ConditionalOnMissingBean
    public Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }
    @Bean
    @Scope("prototype")
    @ConditionalOnMissingBean
    public Feign.Builder feignBuilder(Retryer retryer) {
        return Feign.builder().retryer(retryer);
    }
    @Bean
    @ConditionalOnMissingBean(FeignLoggerFactory.class)
    public FeignLoggerFactory feignLoggerFactory() {
        return new DefaultFeignLoggerFactory(this.logger);
    }
    @Bean
    @ConditionalOnClass(name = "org.springframework.data.domain.Page")
    public Module pageJacksonModule() {
        return new PageJacksonModule();
    }
    @Bean
    @ConditionalOnClass(name = "org.springframework.data.domain.Page")
    public Module sortModule() {
        return new SortJacksonModule();
    }
    @Bean
    @ConditionalOnMissingBean(FeignClientConfigurer.class)
    public FeignClientConfigurer feignClientConfigurer() {
        return new FeignClientConfigurer() {};
    }
    private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
        AbstractFormWriter formWriter = formWriterProvider.getIfAvailable();
        if (formWriter != null) {
            return new SpringEncoder(new SpringPojoFormEncoder(formWriter), this.messageConverters);
        }
        return new SpringEncoder(new SpringFormEncoder(), this.messageConverters);
    }
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
    protected static class HystrixFeignConfiguration {
        @Bean
        @Scope("prototype")
        @ConditionalOnMissingBean
        @ConditionalOnProperty(name = "feign.hystrix.enabled")
        public Feign.Builder feignHystrixBuilder() {
            return HystrixFeign.builder();
        }

    }
    private class SpringPojoFormEncoder extends SpringFormEncoder {
        SpringPojoFormEncoder(AbstractFormWriter formWriter) {
            super();
            MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(MULTIPART);
            processor.addFirstWriter(formWriter);
        }
    }
}

02 开启Feign客户端

Spring Boot通过**@EnableFeignClients**注解开启Feign支持,目的是用于导入处理客户端配置,然后注入到IOC容器。

java 复制代码
@EnableFeignClients
@SpringBootApplication
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class);
    }
}
java 复制代码
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
    // 扫描包路径, 和basePackages属性一致
    String[] value() default {};
    
    // 扫描包路径
    String[] basePackages() default {};
    
    // 基础扫描基础类
    Class<?>[] basePackageClasses() default {};
    
    // 默认配置, 比如申明Decoder、Encoder和Contract
    Class<?>[] defaultConfiguration() default {};
    
    // 客户端配置注解
    Class<?>[] clients() default {};
}

2.1 客户端注册器

Feign使用注册器FeignClientsRegistrar注册默认客户端配置,客户端本地执行远程调用端口,然后注册到IOC容器进行管理。

2.1.1 注册默认配置

Feign通过FeignClientsRegistrar提供默认配置注册,默认为default.[配置类名]进行配置实现。

java 复制代码
class FeignClientsRegistrar 
    implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private Environment environment;
    private ResourceLoader resourceLoader;
    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
        BeanDefinitionRegistry registry) {
        registerDefaultConfiguration(metadata, registry);
        registerFeignClients(metadata, registry);
    }

    private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // 获取@EnableFeignClients注解配置
        Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
        // 获取属性配置
        if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
            String name;
            if (metadata.hasEnclosingClass()) {
                name = "default." + metadata.getEnclosingClassName();
            } else {
                name = "default." + metadata.getClassName();
            }
            registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
        }
    }
    private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
        // 创建BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
        // 添加构建参数值
        builder.addConstructorArgValue(name);
        builder.addConstructorArgValue(configuration);
        // 注册实例
        registry.registerBeanDefinition(
            name + "." + FeignClientSpecification.class.getSimpleName(),
            builder.getBeanDefinition()
        );
    }
}

2.1.2 FeignClient配置

Feign通过FeignClientsRegistrar扫描@FeignClient注解客户端配置,然后创建Feign客户端接口工厂实例Bean定义FeignClientFactoryBean注册到IOC容器。

java 复制代码
public @interface FeignClient {
    // 指定调用服务名称, 对应服务注册中心服务名称
    @AliasFor("name")
    String value() default "";

    // 与name意义一致
    @Deprecated
    String serviceId() default "";

    // 客户端上下文ID, 用于区分不同客户端
    String contextId() default "";

    // value别名
    @AliasFor("value")
    String name() default "";
    
    // 指定客户端限定符, 用于区分相同类型客户端
    String qualifier() default "";
    
    // 指定调用服务URL地址, 直接指定服务URL, 而不通过注册中心进行服务发现
    String url() default "";
    
    // 指定404作为正常响应处理, 默认为false
    boolean decode404() default false;
    
    // 指定客户端配置类, 用于配置客户端相关属性, 如超时时间、重试策略等
    Class<?>[] configuration() default {};
    
    // 指定客户端降级处理类, 远程调用失败降级逻辑
    Class<?> fallback() default void.class;
    
    // 指定客户端降级处理工厂类, 用于创建降级处理类实例
    Class<?> fallbackFactory() default void.class;

    // 指定客户端基础路径, 用于拼接请求URL
    String path() default "";

    // 指定客户端是否为主要的, 当存在多个客户端可以通过primary参数指定主要客户端
    boolean primary() default true;
}
java 复制代码
class FeignClientsRegistrar 
    implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
    private Environment environment;
    private ResourceLoader resourceLoader;
    
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata,
		BeanDefinitionRegistry registry) {
		registerDefaultConfiguration(metadata, registry);
		registerFeignClients(metadata, registry);
	}
    
	public void registerFeignClients(AnnotationMetadata metadata,
		BeanDefinitionRegistry registry) {
		LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
        // 获取属性配置
		Map<String, Object> attrs = metadata
				.getAnnotationAttributes(EnableFeignClients.class.getName());
        // 过滤查找@FeignClient注解属性
		AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
		
        final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
		if (clients == null || clients.length == 0) {
            // 扫描器
			ClassPathScanningCandidateComponentProvider scanner = getScanner();
			scanner.setResourceLoader(this.resourceLoader);
			scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
            // 扫描包
			Set<String> basePackages = getBasePackages(metadata);
			for (String basePackage : basePackages) {
                // 执行包扫描候选类
				candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
			}
		} else {
			for (Class<?> clazz : clients) {
				candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
			}
		}

		for (BeanDefinition candidateComponent : candidateComponents) {
			if (candidateComponent instanceof AnnotatedBeanDefinition) {
				// verify annotated class is an interface
				AnnotatedBeanDefinition bf = (AnnotatedBeanDefinition) candidateComponent;
				AnnotationMetadata amd = bf.getMetadata();
                
                // 必须是接口类
				Assert.isTrue(amd.isInterface(), "@FeignClient can only be specified on an interface");

                // 获取客户端配置@FeignClient
				Map<String, Object> attributes = amd
						.getAnnotationAttributes(FeignClient.class.getCanonicalName());

                // 获取客户端名称
				String name = getClientName(attributes);
                
                // 注册客户端配置
				registerClientConfiguration(registry, name, attributes.get("configuration"));

                // 注册客户端
				registerFeignClient(registry, amd, attributes);
			}
		}
	}

	private void registerFeignClient(BeanDefinitionRegistry registry,
		AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
		String className = annotationMetadata.getClassName();
        // 创建BeanDefinition
		BeanDefinitionBuilder definition = BeanDefinitionBuilder
				.genericBeanDefinition(FeignClientFactoryBean.class);
		validate(attributes);
		definition.addPropertyValue("url", getUrl(attributes));
		definition.addPropertyValue("path", getPath(attributes));
		String name = getName(attributes);
		definition.addPropertyValue("name", name);
		String contextId = getContextId(attributes);
		definition.addPropertyValue("contextId", contextId);
		definition.addPropertyValue("type", className);
		definition.addPropertyValue("decode404", attributes.get("decode404"));
		definition.addPropertyValue("fallback", attributes.get("fallback"));
		definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

		String alias = contextId + "FeignClient";
		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
		beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);

		// has a default, won't be null
		boolean primary = (Boolean) attributes.get("primary");

		beanDefinition.setPrimary(primary);

        // 别名
		String qualifier = getQualifier(attributes);
		if (StringUtils.hasText(qualifier)) {
			alias = qualifier;
		}

		BeanDefinitionHolder bdh = new BeanDefinitionHolder(beanDefinition, className,
				new String[] { alias });
		BeanDefinitionReaderUtils.registerBeanDefinition(bdh, registry);
	}
    
    protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
        // 获取@EnableFeignClients注解
		Map<String, Object> attributes = importingClassMetadata
			.getAnnotationAttributes(EnableFeignClients.class.getCanonicalName());

		Set<String> basePackages = new HashSet<>();
		for (String pkg : (String[]) attributes.get("value")) {
			if (StringUtils.hasText(pkg)) {
				basePackages.add(pkg);
			}
		}
		for (String pkg : (String[]) attributes.get("basePackages")) {
			if (StringUtils.hasText(pkg)) {
				basePackages.add(pkg);
			}
		}
		for (Class<?> clazz : (Class[]) attributes.get("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
		}
		return basePackages;
	}
    // 扫描器
    protected ClassPathScanningCandidateComponentProvider getScanner() {
		return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
			@Override
			protected boolean isCandidateComponent(AnnotatedBeanDefinition abd) {
				if (abd.getMetadata().isIndependent()) {
					if (!abd.getMetadata().isAnnotation()) {
						return true;
					}
				}
				return false;
			}
		};
	}
}

2.2 客户端工厂

Feign创建FeignClientFactoryBean类型BeanDefinition提供客户端实现支持,底层通过代理实现接口方法调用逻辑。

java 复制代码
class FeignClientFactoryBean
	implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
    private Class<?> type;
	private String name;
	private String url;
	private String contextId;
	private String path;
	private boolean decode404;
    // 是否使用父容器上下文
	private boolean inheritParentContext = true;
	private ApplicationContext applicationContext;
	private Class<?> fallback = void.class;
	private Class<?> fallbackFactory = void.class;
	private int readTimeoutMillis = new Request.Options().readTimeoutMillis();
	private int connectTimeoutMillis = new Request.Options().connectTimeoutMillis();

    @Override
	public Object getObject() throws Exception {
		return getTarget();
	}
    
    <T> T getTarget() {
        // 获取FeignContext上下文
		FeignContext context = applicationContext.getBean(FeignContext.class);
		Feign.Builder builder = feign(context);
		if (!StringUtils.hasText(url)) {
			if (!name.startsWith("http")) {
				url = "http://" + name;
			} else {
				url = name;
			}
			url += cleanPath();
			return (T) loadBalance(builder, context, 
                    new HardCodedTarget<>(type, name, url));
		}
		if (StringUtils.hasText(url) && !url.startsWith("http")) {
			url = "http://" + url;
		}
		String url = this.url + cleanPath();
		Client client = getOptional(context, Client.class);
		if (client != null) {
			if (client instanceof LoadBalancerFeignClient) {
				client = ((LoadBalancerFeignClient) client).getDelegate();
			}
			if (client instanceof FeignBlockingLoadBalancerClient) {
				client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
			}
			builder.client(client);
		}
		Targeter tgt = get(context, Targeter.class);
		return (T) tgt.target(this, builder, context, new HardCodedTarget<>(type, name, url));
	}
    protected <T> T get(FeignContext context, Class<T> type) {
		T instance = context.getInstance(contextId, type);
		if (instance == null) {
			throw new IllegalStateException(...);
		}
		return instance;
	}
    protected <T> T getOptional(FeignContext context, Class<T> type) {
		return context.getInstance(contextId, type);
	}
	protected <T> T getInheritedAwareOptional(FeignContext context, Class<T> type) {
		if (inheritParentContext) {
			return getOptional(context, type);
		}
		return context.getInstanceWithoutAncestors(contextId, type);
	}
}
java 复制代码
class FeignClientFactoryBean
	implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
    protected Feign.Builder feign(FeignContext context) {
        // 获取日志LoggerFactory
		FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
		Logger logger = loggerFactory.create(type);

		// @formatter:off
		Feign.Builder builder = get(context, Feign.Builder.class)
				// required values
				.logger(logger)
				.encoder(get(context, Encoder.class))    // 编码器
				.decoder(get(context, Decoder.class))    // 解码器
				.contract(get(context, Contract.class)); // 锲约
		// @formatter:on
        // 配置客户端
		configureFeign(context, builder);

		return builder;
	}
    
    protected void configureFeign(FeignContext context, Feign.Builder builder) {
        // 获取配置
		FeignClientProperties properties = applicationContext.getBean(FeignClientProperties.class);
		FeignClientConfigurer feignClientConfigurer = getOptional(context, FeignClientConfigurer.class);
		setInheritParentContext(feignClientConfigurer.inheritParentConfiguration());

		if (properties != null && inheritParentContext) {
            Map<String, FeignClientConfiguration> config = properties.getConfig();
			if (properties.isDefaultToProperties()) {
				configureUsingConfiguration(context, builder);
				configureUsingProperties(config.get(properties.getDefaultConfig()), builder);
				configureUsingPropertiesconfig.get(contextId), builder);
			} else {
				configureUsingProperties(config.get(properties.getDefaultConfig()), builder);
				configureUsingProperties(config.get(contextId), builder);
				configureUsingConfiguration(context, builder);
			}
		} else {
			configureUsingConfiguration(context, builder);
		}
	}
    protected void configureUsingConfiguration(FeignContext context, Feign.Builder builder) {
		Logger.Level level = getInheritedAwareOptional(context, Logger.Level.class);
		if (level != null) {
			builder.logLevel(level);
		}
		Retryer retryer = getInheritedAwareOptional(context, Retryer.class);
		if (retryer != null) {
			builder.retryer(retryer);
		}
		ErrorDecoder errorDecoder = getInheritedAwareOptional(context, ErrorDecoder.class);
		if (errorDecoder != null) {
			builder.errorDecoder(errorDecoder);
		}
		else {
			FeignErrorDecoderFactory errorDecoderFactory = getOptional(context, FeignErrorDecoderFactory.class);
			if (errorDecoderFactory != null) {
				ErrorDecoder factoryErrorDecoder = errorDecoderFactory.create(type);
				builder.errorDecoder(factoryErrorDecoder);
			}
		}
		Request.Options options = getInheritedAwareOptional(context, Request.Options.class);
		if (options != null) {
			builder.options(options);
			readTimeoutMillis = options.readTimeoutMillis();
			connectTimeoutMillis = options.connectTimeoutMillis();
		}
        // 获取请求拦截器
		Map<String, RequestInterceptor> requestInterceptors = getInheritedAwareInstances(
				context, RequestInterceptor.class);
		if (requestInterceptors != null) {
            // 拦截器
			List<RequestInterceptor> interceptors = new ArrayList<>(requestInterceptors.values());
			AnnotationAwareOrderComparator.sort(interceptors);
			builder.requestInterceptors(interceptors);
		}
		QueryMapEncoder queryMapEncoder = getInheritedAwareOptional(context, QueryMapEncoder.class);
		if (queryMapEncoder != null) {
			builder.queryMapEncoder(queryMapEncoder);
		}
		if (decode404) {
			builder.decode404();
		}
        // 异常传播策略
		ExceptionPropagationPolicy exceptionPropagationPolicy = getInheritedAwareOptional(
				context, ExceptionPropagationPolicy.class);
		if (exceptionPropagationPolicy != null) {
			builder.exceptionPropagationPolicy(exceptionPropagationPolicy);
		}
	}
}

2.3 客户端实例

Feign默认使用DefaultTargeter创建本地方法远程调用客户端,底层创建方法接口JDK代理,仅需通过接口注解信息就可以发起远程方法调用。

java 复制代码
class DefaultTargeter implements Targeter {
	@Override
	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context, Target.HardCodedTarget<T> target) {
		return feign.target(target);
	}
}
java 复制代码
public abstract class Feign {
    public <T> T target(Target<T> target) {
        return build().newInstance(target);
    }
    public static class Builder {
        // ...
        public Feign build() {
            Client client = Capability.enrich(this.client, capabilities);
            Retryer retryer = Capability.enrich(this.retryer, capabilities);
            List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
                    .map(ri -> Capability.enrich(ri, capabilities))
                    .collect(Collectors.toList());
            
            Logger logger = Capability.enrich(this.logger, capabilities);
            Contract contract = Capability.enrich(this.contract, capabilities);
            Options options = Capability.enrich(this.options, capabilities);
            Encoder encoder = Capability.enrich(this.encoder, capabilities);
            Decoder decoder = Capability.enrich(this.decoder, capabilities);
            
            InvocationHandlerFactory invocationHandlerFactory = Capability.enrich(this.invocationHandlerFactory, capabilities);
            QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
            SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
                logLevel, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
            ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
                errorDecoder, synchronousMethodHandlerFactory);
            
            // 创建反射客户端
            return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
        }
    }
}
java 复制代码
public class ReflectiveFeign extends Feign {
    // ...
    @Override
    public <T> T newInstance(Target<T> target) {
        // <客户端, 处理器> 
        Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
        Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<>();
        List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<>();

        for (Method method : target.type().getMethods()) {
            if (method.getDeclaringClass() == Object.class) {
                continue;
            }
            if (Util.isDefault(method)) {
                // 默认处理器
                DefaultMethodHandler handler = new DefaultMethodHandler(method);
                defaultMethodHandlers.add(handler);
                methodToHandler.put(method, handler);
            } else {
                methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
            }
        }
        // 创建代理
        InvocationHandler handler = factory.create(target, methodToHandler);
        T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(),
                new Class<?>[] {target.type()}, handler);
        // 绑定处理器
        for (DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
            defaultMethodHandler.bindTo(proxy);
        }
        return proxy;
    }
}
java 复制代码
static final class ParseHandlersByName {
    // ...
    public Map<String, MethodHandler> apply(Target target) {
        // 获取锲约元数据
        List<MethodMetadata> metadata = contract.parseAndValidateMetadata(target.type());
        Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
        for (MethodMetadata md : metadata) {
            ReflectiveFeign.BuildTemplateByResolvingArgs buildTemplate;
            if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
                buildTemplate = new ReflectiveFeign.BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
            } else if (md.bodyIndex() != null) {
                buildTemplate = new ReflectiveFeign.BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder, target);
            } else {
                buildTemplate = new ReflectiveFeign.BuildTemplateByResolvingArgs(md, queryMapEncoder, target);
            }
            if (md.isIgnored()) {
                result.put(md.configKey(), args -> {
                    throw new IllegalStateException(md.configKey() + " is not a method handled by feign");
                });
            } else {
                result.put(md.configKey(), factory.create(target, md, buildTemplate, options, decoder, errorDecoder));
            }
        }
        return result;
    }
}

static class Factory {
    // ...
    public MethodHandler create(Target<?> target,
        MethodMetadata md, RequestTemplate.Factory buildTemplateFromArgs,
        Options options, Decoder decoder, ErrorDecoder errorDecoder) {
        return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,
                logLevel, md, buildTemplateFromArgs, options, decoder,
                errorDecoder, decode404, closeAfterDecode, propagationPolicy, forceDecoding);
    }
}
java 复制代码
public interface InvocationHandlerFactory {
    InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);
    
    interface MethodHandler {
        Object invoke(Object[] argv) throws Throwable;
    }

    static final class Default implements InvocationHandlerFactory {
        @Override
        public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
            return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
        }
    }
}
java 复制代码
static class FeignInvocationHandler implements InvocationHandler {
    private final Target target;
    private final Map<Method, InvocationHandlerFactory.MethodHandler> dispatch;

    FeignInvocationHandler(Target target, Map<Method, InvocationHandlerFactory.MethodHandler> dispatch) {
        this.target = checkNotNull(target, "target");
        this.dispatch = checkNotNull(dispatch, "dispatch for %s", target);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("equals".equals(method.getName())) {
            try {
                Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                return equals(otherHandler);
            } catch (IllegalArgumentException e) {
                return false;
            }
        } else if ("hashCode".equals(method.getName())) {
            return hashCode();
        } else if ("toString".equals(method.getName())) {
            return toString();
        }
        // 获取方法处理器, 进行调用处理 
        return dispatch.get(method).invoke(args);
    }
}
相关推荐
fanly111 天前
Surging AI Agent 完整产品介绍
微服务·microservice
吃饱了得干活3 天前
Spring Cloud Gateway 微服务网关:路由、断言、过滤器
java·spring cloud
蝎子莱莱爱打怪8 天前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
SamDeepThinking9 天前
Java微服务练习方式
java·后端·微服务
米丘12 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质14 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
慧一居士15 天前
Feign的GET请求如何传递对象参数?
java·spring cloud
我登哥MVP15 天前
SpringCloud Alibaba 核心组件解析:服务链路追踪
java·spring boot·后端·spring·spring cloud·java-ee·maven
慧一居士15 天前
SpringCloud 微服务Feigin 用的完整调用端和被调用的示例
java·spring cloud
霸道流氓气质15 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化