微服务组件源码3——OpenFeign的原理
1、概述

* 代码架构
- 顶级接口Client表示一个通信客户端,只有一个execute方法,其实现类有多种,有提供最基本通信功能的ApacheClient、OKhttpClient、
- 还有其他装饰过的实现类,如提供负载均衡的通信客户端LoadBlancerFeignClient,对基本Client进行再次封装,负载功能由FeignLoadBlancer提供
其核心的选择服务实例的还能就是由ILoadBalancer总控组件提供,这一点和Spring Ribbon是一样的
* OpenFeign只是对 HTTP 调用组件进行了易用性封装,底层还是使用我们常见的 OkHttp、HttpClient 、ILoadBalancer总控负载组件等组件
* OpenFeign的目标之一就让这些 HTTP 客户端更好用,使用方式更统一,更像RPC。
2、@EnableFeignClients注解开启
@EnableFeignClients("com.kaka")
@SpringBootApplication
public class ConsumerApplication{
public static void main(String[] args){
SpringApplication.run(ConsumerApplication.class, args);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
//@FeignClient注解的接口路径指定
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] clients() default {};
//全局默认配置类
Class<?>[] defaultConfiguration() default {};
}
2.1、注册(全局/特定)FeignClientSpecification类bean定义
class FeignClientSpecification implements NamedContextFactory.Specification {
private String name;
private Class<?>[] configuration;
}
主要流程
* 注册默认的FeignClient配置类定义——@EnableFeignClients注解指定
- 获取@EnableFeignClients主注解上defaultConfiguration指定的类,注册bean定义到容器中
创建bean定义,bean名称为default + defaultConfiguration类名 + FeignClientSpecification,类型为FeignClientSpecification,构造参数为defaultConfiguration指定的类。
- FeignClientSpecification中对应name属性值为default + defaultConfiguration类名
@EnableFeignClients(defaultConfiguration = xxx.class)
public class xxx { }
* 注册特定客户端的配置类定义,注册到容器中——@FeignClient注解指定
- 创建bean定义,名称取值(为空依次取contextId\value\name\serviceId属性值)+FeignClientSpecification,类型为FeignClientSpecification,
- 构造参数为configuration属性指定的类(可能为null);name属性为取值(为空依次取contextId\value\name\serviceId属性值)
@FeignClient(value = "openFeign-provider",configuration = xx.class)
public interface OpenFeignService {}
2.2、注册FeignClient接口的bean定义
* 获取扫描的范围,接着进行注册
- 如果@EnableFeignClients注解的clients为空
- 获取@EnableFeignClients主键的value、basePackages、basePackageClasses属性指定的包路
如果都为空就默认使用标志此注解的类本身路径,扫描添加了@FeignClient注解的接口
- 如果@EnableFeignClients注解的clients不为空,则扫描指定客户端类
* 向容器创建注册@FeignClient接口对应的使用BeanDefinition,使用FactoryBean工厂bean的形式,将Bean的具体生成过程收拢到FeignClientFactoryBean之中
- 使用type类名做bean定义的名称,为空依序获取serviceId\name\value作为值,再+FeignClient作为别名
- 获取每一个@FeignClient(其部分功能和@RibbonClien注解类似)的属性值,以addPropertyValue(setter注入属性,即AUTO_BY_TYPE形式)形式封装为
AbstractBeanDefinition注册到容器中,比如
type(类名)、name(依序获取serviceId\name\value)
contextId(如果contextId为空,使用依序获取serviceId\name\value作为值)、
url、path、fallback等直接取值
@FeignClient(value = "openFeign-provider",contextId = "openFeign-provide" ,path = "/test",configuration = xx.class,fallbackFactory = xx.class)
public interface OpenFeignService {
@PostMapping("/openfeign/provider/order2")
Order createOrder2(@RequestBody Order order);
}
- 需要注意的是,fallbackFactory/fallback只有在支持hystrix下才有效,由feign.hystrix.FallbackFactory也可见
@ConditionalOnMissingClass("feign.hystrix.HystrixFeign")
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
FeignClientsRegistrar() {
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);
registerFeignClients(metadata, registry);
}
private void registerDefaultConfiguration(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
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"));
}
}
public void registerFeignClients(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
final Class<?>[] clients = attrs == null ? null: (Class<?>[]) attrs.get("clients");
//如果@EnableFeignClients注解的clients为空
if (clients == null || clients.length == 0) {
scanner.addIncludeFilter(annotationTypeFilter);
//获取@EnableFeignClients主键的value、basePackages、basePackageClasses属性指定的包路,如果都为空使用标志此注解的类本身路径
//扫描添加了@FeignClient注解的类
basePackages = getBasePackages(metadata);
}
else {
//指定clients客户端类的处理
final Set<String> clientClasses = new HashSet<>();
basePackages = new HashSet<>();
for (Class<?> clazz : clients) {
basePackages.add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
@Override
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
}
for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
// verify annotated class is an interface
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
//为空依次取contextId\value\name\serviceId;
String name = getClientName(attributes);
//使用name+FeignClientSpecification作为bean定义名,FeignClientSpecification为bean类型,封装了指定的配置类
registerClientConfiguration(registry, name,attributes.get("configuration"));
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("path", getPath(attributes));
//依序获取serviceId\name\value作为name
String name = getName(attributes);
definition.addPropertyValue("name", name);
//如果contextId为空,使用依序获取serviceId\name\value作为值
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();
boolean primary = (Boolean) attributes.get("primary");
beanDefinition.setPrimary(primary);
String qualifier = getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,new String[] { alias });
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
protected ClassPathScanningCandidateComponentProvider getScanner() {
return new ClassPathScanningCandidateComponentProvider(false, this.environment) {
@Override
protected boolean isCandidateComponent(
AnnotatedBeanDefinition beanDefinition) {
boolean isCandidate = false;
if (beanDefinition.getMetadata().isIndependent()) {
if (!beanDefinition.getMetadata().isAnnotation()) {
isCandidate = true;
}
}
return isCandidate;
}
};
}
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(),builder.getBeanDefinition());
}
}
可以看出,关键逻辑又回到 FeignClientFactoryBean 拿到业务接口、@EnableFeignClient 和 @FeignClient 的数据后如何去构造代理类了,而 FeignClientFactoryBean 内部其实使用的是原生 Feign 的 API 来构建代理对象。
3、自动配置
配置的加载顺序如下
注:FeignRibbonClientAutoConfiguration 和FeignLoadBalancerAutoConfiguration功能基本一致,一般以FeignRibbonClientAutoConfiguration 为主

3.1 FeignRibbonClientAutoConfiguration
在存在ILoadBalancer.class, Feign.class的时候会进行加载,作用是
* 创建CachingSpringLoadBalancerFactory,用于创建FeignLoadBalancer对象
* 开启FeignHttpClientProperties类型属性对象,收集feign.httpclient.xxxx配置
其超时配置会作用于底层httpClient客户端
* 依情况注入feign.Client接口的3个实现类,以HttpClientFeignLoadBalancedConfiguration为例,存在ApacheHttpClient类时会新建
①导入HttpClientFeignConfiguration,会使用ApacheHttpClien适配底层的HttpClient(CloseableHttpClient)接口的实现类
此HttpClient对象可能会被FeignAutoConfiguration配置的HttpClient bean覆盖,但没关系,两者的创建内容是一样的,
②会创建feign.Client底层接口的实现类,实现类型为LoadBalancerFeignClient,构造参数如下
- HttpClient:委托对象,为①创建ApacheHttpClient(CloseableHttpClient)适配类;
- SpringClientFactory :ribbon组件创建工厂,这个在RibbonAutoConfiguration里会创建,这里也包含了Ribbon的所有功能,是Feign基于Ribbon的最大原因;
- CachingSpringLoadBalancerFactory:这个在FeignRibbonClientAutoConfiguration里会创建
@ConditionalOnClass({ ILoadBalancer.class, Feign.class })
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.ribbon.enabled",
matchIfMissing = true)
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@EnableConfigurationProperties({ FeignHttpClientProperties.class })
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
OkHttpFeignLoadBalancedConfiguration.class,
DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {
@Bean
@Primary
@ConditionalOnMissingBean
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
public CachingSpringLoadBalancerFactory cachingLBClientFactory(
SpringClientFactory factory) {
return new CachingSpringLoadBalancerFactory(factory);
}
@Bean
@Primary
@ConditionalOnMissingBean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
public CachingSpringLoadBalancerFactory retryabeCachingLBClientFactory(
SpringClientFactory factory, LoadBalancedRetryFactory retryFactory) {
return new CachingSpringLoadBalancerFactory(factory, retryFactory);
}
@Bean
@ConditionalOnMissingBean
public Request.Options feignRequestOptions() {
return LoadBalancerFeignClient.DEFAULT_OPTIONS;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
@Import(HttpClientFeignConfiguration.class)
class HttpClientFeignLoadBalancedConfiguration {
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, HttpClient httpClient) {
ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(CloseableHttpClient.class)
public class HttpClientFeignConfiguration {
private final Timer connectionManagerTimer = new Timer(
"FeignApacheHttpClientConfiguration.connectionManagerTimer", true);
private CloseableHttpClient httpClient;
@Autowired(required = false)
private RegistryBuilder registryBuilder;
@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
@ConditionalOnProperty(value = "feign.compression.response.enabled",
havingValue = "false", matchIfMissing = true)
public CloseableHttpClient httpClient(ApacheHttpClientFactory httpClientFactory,
HttpClientConnectionManager httpClientConnectionManager,
FeignHttpClientProperties httpClientProperties) {
this.httpClient = createClient(httpClientFactory.createBuilder(),
httpClientConnectionManager, httpClientProperties);
return this.httpClient;
}
private CloseableHttpClient createClient(HttpClientBuilder builder,
HttpClientConnectionManager httpClientConnectionManager,
FeignHttpClientProperties httpClientProperties) {
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setConnectTimeout(httpClientProperties.getConnectionTimeout())
.setRedirectsEnabled(httpClientProperties.isFollowRedirects()).build();
CloseableHttpClient httpClient = builder
.setDefaultRequestConfig(defaultRequestConfig)
.setConnectionManager(httpClientConnectionManager).build();
return httpClient;
}
}
3.2 FeignAutoConfiguration
与RibbonAutoConfiguration配置类似
* 收集配置类List<FeignClientSpecification> configurations
收集@EnableFeignClients、@FeignClient定义封装好的配置类
* 启动文件配置
- 启动FeignClientProperties属性配置feign.client.xxxx
- 启动FeignHttpClientProperties属性配置feign.httpclient.xxxx
* 创建FeignContext extends NamedContextFactory<FeignClientSpecification>
和SpringClientFactory类似,这里为每一个指定的name 创建一个上下文,里面会注册配置表中指定name和默认FeignClientsConfiguration默认配置的数据
每个上下文里包含可每一个服务独自指定的和全局默认的配信息,如 Logger.Level:日志级别、 Retryer: 重试机制、Client:Http客户端接口、Decoder:解码器等
* Targeter类的创建
会依据是否存在feign.hystrix.HystrixFeign类来创建DefaultTargeter或者HystrixTargeter实现类
* feign.Client接口的实现类,和FeignRibbonClientAutoConfiguration里的类似,
- 比如会根据是否有ApacheHttpClient,会使用ApacheHttpClien适配底层的HttpClient(CloseableHttpClient)接口的实现类
创建逻辑是独立的,是和Feign没有强关联。
- 注意这里创建的ApacheHttpClient会使用FeignHttpClientProperties(feign.httpclient.xxxx)属性类的值
例如超时时间、连接池相关的设置
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Feign.class)
@EnableConfigurationProperties({ FeignClientProperties.class,
FeignHttpClientProperties.class })
@Import(DefaultGzipDecoderConfiguration.class)
public class FeignAutoConfiguration {
@Autowired(required = false)
private List<FeignClientSpecification> configurations = new ArrayList<>();
@Bean
public HasFeatures feignFeature() {
return HasFeatures.namedFeature("Feign", Feign.class);
}
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "feign.hystrix.HystrixFeign")
protected static class HystrixFeignTargeterConfiguration {
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new HystrixTargeter();
}
}
@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)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnMissingBean(CloseableHttpClient.class)
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
protected static class HttpClientFeignConfiguration {
private final Timer connectionManagerTimer = new Timer(
"FeignApacheHttpClientConfiguration.connectionManagerTimer", true);
@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);
}
@PreDestroy
public void destroy() throws Exception {
this.connectionManagerTimer.cancel();
if (this.httpClient != null) {
this.httpClient.close();
}
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
protected static class OkHttpFeignConfiguration {
private okhttp3.OkHttpClient okHttpClient;
@Bean
@ConditionalOnMissingBean(ConnectionPool.class)
public ConnectionPool httpClientConnectionPool(
FeignHttpClientProperties httpClientProperties,
OkHttpClientConnectionPoolFactory connectionPoolFactory) {
Integer maxTotalConnections = httpClientProperties.getMaxConnections();
Long timeToLive = httpClientProperties.getTimeToLive();
TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
}
@Bean
public okhttp3.OkHttpClient client(OkHttpClientFactory httpClientFactory,
ConnectionPool connectionPool,
FeignHttpClientProperties httpClientProperties) {
Boolean followRedirects = httpClientProperties.isFollowRedirects();
Integer connectTimeout = httpClientProperties.getConnectionTimeout();
Boolean disableSslValidation = httpClientProperties.isDisableSslValidation();
this.okHttpClient = httpClientFactory.createBuilder(disableSslValidation)
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.followRedirects(followRedirects).connectionPool(connectionPool)
.build();
return this.okHttpClient;
}
@PreDestroy
public void destroy() {
if (this.okHttpClient != null) {
this.okHttpClient.dispatcher().executorService().shutdown();
this.okHttpClient.connectionPool().evictAll();
}
}
@Bean
@ConditionalOnMissingBean(Client.class)
public Client feignClient(okhttp3.OkHttpClient client) {
return new OkHttpClient(client);
}
}
}
3.3 FeignClientsConfiguration默认Name容器配置
包括了Fegin可配置的所有组件:
* Decoder解码器
默认为OptionalDecoder,用于把远程的repose转为feign接口方法对应的类型
* SpringEncoder编码器
- 默认为SpringEncoder,会接受容器中的ObjectFactory<HttpMessageConverters> HttpMessageConverters
- 会把请求体数据(可以从feign接口参数中获取到)转换为request中指定ContentType的数据格式,作为RequestTemplate的body
*Contract请求信息解析器
- 默认为SpringMvcContract,可以结合SpringMVC的相关注解,把一个feign接口解析为List<MethodMetadata>,一个方法对应个MethodMetadata
- MethodMetadata里包含一个RequestTemplate template和方法上的信息
①RequestTemplate即请求模板,基于SpringMVC约定的注解,可以获取到template().uri/header/method()信息
②方法上的信息:如普通参数(作为请求体)的参数位置下标,所有@Param的name存于List<String> formParams,
添加了@QueryMap/HeaderMap注解的参数的位置
* Builder构造者
- 默认为Feign.builder,用于配置contract/Client /Retryer/Logger/Encoder/Decoderd等,最后封装到ReflectiveFeign对象中
@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() {
return new SpringEncoder(this.messageConverters);
}
@Bean
@ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
@ConditionalOnMissingBean
public Encoder feignEncoderPageable() {
PageableSpringEncoder encoder = new PageableSpringEncoder(
new SpringEncoder(this.messageConverters));
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();
}
@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();
}
}
}
4、@FeignClient代理类创建(基于FeignClientFactoryBean)
4.1、概述
* 在@EnableFeignClients注解阶段就把@FeignClient接口转为FeignClientFactoryBean注册容器中了
封装好了从@FeignClient注解解析后的所有属性:
@FeignClient(value/name = "openFeign-provider",contextId = "openFeign-provide" ,path = "/test",configuration = xx.class,fallbackFactory = xx.class)
private Class<?> type;
private String name;
private String url;
private String contextId;
private String path;
private boolean decode404;
private ApplicationContext applicationContext;
private Class<?> fallback = void.class;
private Class<?> fallbackFactory = void.class;
* Fegin 使用的是 JDK 动态代理技术来生成实现类的,因此 Feign 的使用必须要有接口,一个feign接口每个方法有 @RequestMapping
虽然我们可以在 java.lang.reflect.InvocationHandler#invoke 的方法入参 Method 中去解析 @RequestMapping 拿url,
但需要注意的是,大多数开源框架很忌讳在运行时高频使用JDK的反射,因为这样非常影响执行效率,
所以在 Feign 使用 JDK动态代理技术时,需要提前将接口带 @RequestMapping 方法解析出来。
4.2、Feign.Builder组件封装对象
步骤如下:
* 获取feign上下文容器FeignContext context,以每一个ContextId为key,即每一个ContextId一个单独的容器上下文
* 基于FeignContext和文件属性配置类获取用户定义或者默认的组件实现类,存于Builder中
- 从Name容器中获取Feign.Builder
- 组装必须组件Logger、Encoder、Decoder、Contract
Feign.Builder builder = get(context, Feign.Builder.class).logger(logger).encoder(get(context, Encoder.class)).decoder(get(context, Decoder.class)).contract(get(context, Contract.class));
- 组装可选组件
获取父Spring容器中获取FeignClientProperties(在FeignAutoConfiguration 中会启用),即feign.client.xxx
会从不同维度依次获取Logger.Level、Retryer、ErrorDecoder、Request.Options、RequestInterceptor、QueryMapEncoder组装到Feign.Builder,后面的会覆盖前面的
①从Name容器中获取可选组件
②获取feign.client.default.xxxx,映射为FeignClientConfiguration对象,从此配置中获取可选组件
③获取feign.client.contextId.xxxx,映射为FeignClientConfiguration对象,从此配置中获取可选组件
如果此FeignClientProperties为全局默认,即feign.client.defaultToProperties = true;--默认,走①②③
如果此FeignClientProperties不为全局默认,走②③
如果此FeignClientProperties不存在,走①
* 判断是否配置了url属性,选择不同的HttpClient,进行组装builder.client(client);
①如果没有,使用增强的HttpClient进行访问。比如提供负载均衡的客户端LoadBalancerFeignClient类,所有需要使用基于服务实例的负载均衡进行通信
- 会拼接name/name属性和path属性到url属性中,例如this.url = http://openFeign-provider/test
简单的封装到HardCodedTarget(this.type--接口类型, this.name, this.url)
- 从Name容器(没有就到Spring容器)中获取feign.Client类型对象,例如FeignRibbonClientAutoConfiguration引入的LoadBalancerFeignClient
其内部委托了实际的通信工具ApacheHttpClient
②如果存在url,流程和①类似,区别在于此时feign.Client类型对象取的其委托委托了实际的通信工具
使用LoadBalancerFeignClient/FeignBlockingLoadBalancerClient内部委托的,使用其.getDelegate()获取到底层没有负载功能的feign.Client类型对象
比如LoadBalancerFeignClient的委托类ApacheHttpClient,适配底层的HttpClient(CloseableHttpClient)实例从而实现了feign.Client类型,是没有负载均衡功能的
* 最后使用Targeter进行目标代理,会根据是否存在feign.hystrix.HystrixFeign类获取DefaultTargeter或者HystrixTargeter---流程见下节
- targeter.target(this, builder, context, HardCodedTarget(this.type--接口类型, this.name, this.url));
- 例如DefaultTargete会使用(Feign.Builder)feign.target(target)会创建this.type--接口类型的接口代理类,增强类是FeignInvocationHandler
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 ApplicationContext applicationContext;
private Class<?> fallback = void.class;
private Class<?> fallbackFactory = void.class;
@Override
public Object getObject() throws Exception {
return getTarget();
}
<T> T getTarget() {
//获取feign容器
FeignContext context = this.applicationContext.getBean(FeignContext.class);
//根据配置的优先级在Builder中设置各个组件的实现
Feign.Builder builder = feign(context);
//如果没有url属性,使用增强的cilent进行访问。比如提供负载均衡的客户端LoadBalancerFeignClient类
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
this.url = "http://" + this.name;
}
else {
this.url = this.name;
}
//拼接name属性和path属性
this.url += cleanPath();
//这里builder.client(client);client提供负载均衡的客户端,之后使用targeter.target进行代理
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
//如果存在url,使用底层的HttpClient进行直接访问
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.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 targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context,
new HardCodedTarget<>(this.type, this.name, url));
}
protected Feign.Builder feign(FeignContext context) {
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
Logger logger = loggerFactory.create(this.type);
//添加必要的组件
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));
//根据文件配置、java配置类进行配置,按照优先级进行覆盖,代码略
configureFeign(context, builder);
return builder;
}
protected <T> T get(FeignContext context, Class<T> type) {
T instance = context.getInstance(this.contextId, type);
if (instance == null) {
throw new IllegalStateException(
"No bean found of type " + type + " for " + this.contextId);
}
return instance;
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, target);
}
throw new IllegalStateException();
}
//getter、setter略
}
4.3、使用Targete创建代理类流程(默认DefaultTargeter)
4.3.1 Targeter接口

* 作用
用于创建feign接口的代理类,会先解析相关必要的信息,在代理增强逻辑中进行调用,从而完成这个通信流程
* target接口参数如下,返回T就是最终代理类
- FeignClientFactoryBean:feign代理接口对应的FactoryBean,里面封装好了从@FeignClient注解解析后的所有属性:
@FeignClient(value/name = "openFeign-provider",contextId = "openFeign-provide" ,path = "/test",configuration = xx.class,fallbackFactory = xx.class)
- Feign.Builder构造者:里面包含的一个feign代理类所需的所有必要的组件和可选组件
组装必须组件Logger、Encoder、Decoder、Contract
组装可选组件Logger.Level、Retryer、ErrorDecoder、Request.Options、RequestInterceptor、QueryMapEncoder
- FeignContext context:feign的Name容器功能,可以获取一个contextId(如果contextId为空,使用依序获取serviceId\name\value作为值)维度的容器中的bean
- HardCodedTarget(this.type--接口类型, this.name, this.url):简单的包装类,此this.url为 http://服务名/path;或者http://直接域名/path;
* 调用时机
在FeignClientFactoryBean的getObject()中就会处理好target接口这个所需的所有参数(见上),在调用此接口经常创建最终的代理类
interface Targeter {
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target);
}
4.3.2 DefaultTargeter实现类
代理类会根据调用的方法来直接找到已经提前准备好的对应的 MethodHandler,直接调用即可完成Feign的使命,根据上面的使用方法,我们不难猜到 MethodHandler 里面有HTTP调用的相关信息(这些信息之前是在接口方法定义的 @RequestMapping 或 @RequestLine 之中),而且 MethodHandler#invoke 会完成真正的HTTP调用并将结果反序列化成原接口方法的返回值对象
* 使用DefaultTargeter的target方法,底层为Feign.Builder类target方法
- 使用build()方法创建ReflectiveFeign
- 在使用此ReflectiveFeign的newInstance(target)创建代理
//DefaultTargeter
class DefaultTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
return feign.target(target);
}
}
//Feign.Builder类的feign.target(target)
public <T> T target(Target<T> target) {
return build().newInstance(target);
}
4.3.2.1 ReflectiveFeign的build构建
* 基于ReflectiveFeign创建最终代理类的实现,先调用build()创建ReflectiveFeign,会创建好ReflectiveFeign所需的参数
①SynchronousMethodHandler.Factory synchronousMethodHandlerFactory
- new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy);
- 是一个简单的工厂类,里面的create方法就会返回一个SynchronousMethodHandler,其内也包含了这些参数配置
②ParseHandlersByName handlersByName
- new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,errorDecoder, synchronousMethodHandlerFactory);
- 也是一个简单的包装类,唯一的方法apply用于解析一个feign接口,解析每一个方法为一个对应的MethodHandler(见下节)
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
③创建ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder)
其中InvocationHandlerFactory默认为InvocationHandlerFactory.Default();
public Feign build() {
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory = new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,
logger,logLevel, decode404, closeAfterDecode, propagationPolicy);
ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
static class Factory {
private final Client client;
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final Logger logger;
private final Logger.Level logLevel;
private final boolean decode404;
private final boolean closeAfterDecode;
private final ExceptionPropagationPolicy propagationPolicy;
Factory(Client client, Retryer retryer, List<RequestInterceptor> requestInterceptors,
Logger logger, Logger.Level logLevel, boolean decode404, boolean closeAfterDecode,
ExceptionPropagationPolicy propagationPolicy) {
this.client = checkNotNull(client, "client");
this.retryer = checkNotNull(retryer, "retryer");
this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors");
this.logger = checkNotNull(logger, "logger");
this.logLevel = checkNotNull(logLevel, "logLevel");
this.decode404 = decode404;
this.closeAfterDecode = closeAfterDecode;
this.propagationPolicy = propagationPolicy;
}
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);
}
}
4.3.2.2 调用ReflectiveFeign.newInstance创建代理类
①基于ParseHandlersByName为每一个方法创建MethodHandler(默认为SynchronousMethodHandler)
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
②在形成方法反射对象method到MethodHandler的映射结果Map<Method, MethodHandler> methodToHandler
- 如果是public非abstract,非synthetic,非static 的方法,且是interface方法,使用DefaultMethodHandler类作为MethodHandler(也是一个增强)
即非接口方法的代理实际上是直接调用原对象的方法
- 如果是接口指定的方法,在methodToHandler中找到对应方法的处理类
methodToHandler从ParseHandlersByName.apply返回的结果集中获取,如果获取不到就使用原menthod
③使用InvocationHandlerFactory的create(target, methodToHandler)创建InvocationHandler增强类
new ReflectiveFeign.FeignInvocationHandler(target, methodToHandler);
④使用JDK代理创建工具创建增强类,其invoke方法就是根据需要调用的方法method从methodToHandler获取对应的MethodHandler,调用MethodHandler.invoke(args)
- InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[] {target.type()}, handler);
- 增强功能最终调用的是SynchronousMethodHandler.invoke
public class ReflectiveFeign extends Feign {
private final ParseHandlersByName targetToHandlersByName;
private final InvocationHandlerFactory factory;
private final QueryMapEncoder queryMapEncoder;
ReflectiveFeign(ParseHandlersByName targetToHandlersByName, InvocationHandlerFactory factory, QueryMapEncoder queryMapEncoder) {
this.targetToHandlersByName = targetToHandlersByName;
this.factory = factory;
this.queryMapEncoder = queryMapEncoder;
}
@SuppressWarnings("unchecked")
@Override
public <T> T newInstance(Target<T> target) {
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) {
continue;
} else 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;
}
static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, MethodHandler> dispatch;
FeignInvocationHandler(Target target, Map<Method, 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);
}
//略
}
4.4、MethodHandler的创建
4.4.1 整体流程
Map<String, MethodHandler> nameToHandler = ParseHandlersByName.apply(target);
使用ParseHandlersByName的apply方法生成每个接口方法的MethodHandler,MethodHandler的默认实现为SynchronousMethodHandler
* 使用contract.parseAndValidatateMetadata获取每个接口方法的元数据MethodMetadata
- 包括RequestTemplate、接口方法的返回类类型,以及经过对注解等信息获取每个方法对应的url、请求头、请求体等信息及参数位置下标
- Contract的默认实现是SpringMvcContract,它支持解析@RequestMapping等注解,获取相关的信息
* 遍历每一个MethodMetadata,解析为对应的BuildTemplateByResolvingArgs
- !md.formParams().isEmpty() && md.template().bodyTemplate() == null) ,即存在form且不存在请求体时
封装为BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
- md.bodyIndex() != null,即存在feign接口存在指定请求体参数时
封装为BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
- 其余情况
封装为BuildTemplateByResolvingArgs(md, queryMapEncoder);
* 使用MethodHandler工厂创建把每一个MethodMetadata创建对应的MethodHandler,其中参数包含了所有feign组件已经上一步解析后的BuildTemplateByResolvingArgs
new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,
logLevel, md, buildTemplateFromArgs, options, decoder,
errorDecoder, decode404, closeAfterDecode, propagationPolicy);
* 返回解析后的Map<方法标志key, MethodHandler>
public Map<String, MethodHandler> apply(Target key) {
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
}
result.put(md.configKey(),
factory.create(key, md, buildTemplate, options, decoder, errorDecoder));
}
return result;
}
}
4.4.2 MethodMetadata元数据类(以SpringMvcContract解析为例)
class MethodMetadata {
// key名=》OrderFeign#post(Order)
private String configKey;
// 方法返回类型=》Order
private transient Type returnType;
// URL类型的参数的下标
private Integer urlIndex;
// 请求体位置(不同类型的对象(没有标注http相关注解)。只能有一个),但可以存在多个Optional类型的参数
private Integer bodyIndex;
// 请求体类型
private transient Type bodyType;
// 消息头位置(表示请求头的参数的位置)、HeaderMap/RequestHeader注解、
private Integer headerMapIndex;
// queryMap位置,最终会作为url的查询参数(在RequestTemplate的queries--会作为"&"查询参数),例如带有@SpringQueryMap参数、带有@RequestParam且为Map类型的参数
private Integer queryMapIndex;
private boolean queryMapEncoded;
// 请求模板,会在里面存储解析收数据 例如method、url(从@RequestMapping的value)、@RequestParam注解指定的值(在RequestTemplate的queries)会存于此,template().query(name, query))
、从@RequestMapping获取ACCEP/等、Feign中的scheme(即协议类型,如http或https)通常由接口方法上的URL注解指定,如果没有指定,Feign会尝试从配置中获取默认的scheme。如果配置中也没有指定,Feign默认使用http协议
private final RequestTemplate template = new RequestTemplate();
// @PathVariable的value/name的名称,此name名称在RequestTemplate的queries和heards都不存在值时,且url上的#部分不存在,会加入此formParams
private final List<String> formParams = new ArrayList();
//@Param、@PathVariabl、@RequestHeader、@RequestParam中的value/name的名称都会存于此(已经对应的参数下标)
private final Map<Integer, Collection<String>> indexToName = new LinkedHashMap();
//对于http功能的注解(如@PathVariable)的参数,会有一个对应Expander,用于把此值转为String
private final Map<Integer, Class<? extends Expander>> indexToExpanderClass = new LinkedHashMap();
private final Map<Integer, Boolean> indexToEncoded = new LinkedHashMap();
//基于conversionService获取能够把参数类转为字符串的转换器器,如果没有为null
private transient Map<Integer, Expander> indexToExpander;
private BitSet parameterToIgnore = new BitSet();
// 是否忽略该方法
private boolean ignored;
// 需要代理的接口类型
private transient Class<?> targetType;
// 接口中的方法 =》public abstract pojo.Order account.OrderFeign.post(pojo.Order)
private transient Method method;
// 警告级别
private final transient List<String> warnings = new ArrayList();
}
4.4.3 Contract解析阶段为MethodMetadata集合(SpringMvcContract实现)
4.4.3.1 Contract 接口

只有一个parseAndValidatateMetadata方法,用于把指定的Feign接口类生成List<MethodMetadata>
public interface Contract {
List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType);
}
4.4.3.2 BaseContract类
实现了parseAndValidatateMetadata整体实现流程:
* 接口的校验
接口上不能有泛型变量、接口最多有一个父接口、父接口存在时,父接口的父接口不能存在
* 开始遍历每一个接口方法,需要过滤掉Object的方法、static方法、default(default是指public非abstract,非synthetic,非static 的方法,且是interface方法)方法
调用parseAndValidateMetadata进行解析成MethodMetadata
①设置好MethodMetadata的targetType(即Feign接口类型)、method(反射方法)、returnType、configKey
②调用抽象方法processAnnotationOnClass处理接口(包括父接口)上的注解
③调用抽象方法processAnnotationOnMethod处理接口方法的每一个注解
④处理接口参数的注解,遍历每一个参数,接口参数一般分为几类:标记了http相关注解的;URI类型的;Request.Options类型的,普通类型
- 执行调用抽象方法processAnnotationsOnParameter判断参数注解是否属于isHttpAnnotation(默认flase)
- 如果参数类型是否是URI,有了就设置MethodMetadata的urlIndex为此参数位置
- 如果参数是标记了http相关注解(isHttpAnnotation为true)的且为非Request.Options类型的,即普通类型的
会设置为MethodMetadata的bodyIndex和bodyType,只能设置一次,多个会报错
⑤如果MethodMetadata .headerMapIndex()或者queryMapIndex存在
进行headerMap和queryMap进行Map类型的校验,只允许此参数类型为Map<String,String>类
abstract class BaseContract implements Contract {
@Override
public List<MethodMetadata> parseAndValidateMetadata(Class<?> targetType) {
//接口上不能有泛型变量
checkState(targetType.getTypeParameters().length == 0, "Parameterized types unsupported: %s",targetType.getSimpleName());
//接口最多有一个父接口
checkState(targetType.getInterfaces().length <= 1, "Only single inheritance supported: %s",targetType.getSimpleName());
//父接口存在时,父接口的父接口不能存在
if (targetType.getInterfaces().length == 1) {
checkState(targetType.getInterfaces()[0].getInterfaces().length == 0,"Only single-level inheritance supported: %s",targetType.getSimpleName());
}
final Map<String, MethodMetadata> result = new LinkedHashMap<String, MethodMetadata>();
//遍历接口方法
for (final Method method : targetType.getMethods()) {
//过滤掉Object的方法、static方法、default(default是指public非abstract,非synthetic,非static 的方法,且是interface方法)方法
if (method.getDeclaringClass() == Object.class ||(method.getModifiers() & Modifier.STATIC) != 0 ||Util.isDefault(method)) {
continue;
}
//解析出每个方法的元数据 MethodMetadata
final MethodMetadata metadata = parseAndValidateMetadata(targetType, method);
checkState(!result.containsKey(metadata.configKey()), "Overrides unsupported: %s",metadata.configKey());
result.put(metadata.configKey(), metadata);
}
return new ArrayList<>(result.values());
}
//解析出每个方法的元数据 MethodMetadata
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
final MethodMetadata data = new MethodMetadata();
data.targetType(targetType);
data.method(method);
data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
data.configKey(Feign.configKey(targetType, method));
if (targetType.getInterfaces().length == 1) {
//处理父接口上的注解,留给子类实现
processAnnotationOnClass(data, targetType.getInterfaces()[0]);
}
//处理当前接口上的注解,留给子类实现
processAnnotationOnClass(data, targetType);
for (final Annotation methodAnnotation : method.getAnnotations()) {
//处理接口方法上的注解,留给子类实现
processAnnotationOnMethod(data, methodAnnotation, method);
}
if (data.isIgnored()) {return data;
}
checkState(data.template().method() != null,"Method %s not annotated with HTTP method type (ex. GET, POST)%s",data.configKey(), data.warnings());
//方法参数类型
final Class<?>[] parameterTypes = method.getParameterTypes();
final Type[] genericParameterTypes = method.getGenericParameterTypes();
//参数注解:Annotation[i][j]表示第i个参数的注解集合
final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
final int count = parameterAnnotations.length;
for (int i = 0; i < count; i++) {
boolean isHttpAnnotation = false;
if (parameterAnnotations[i] != null) {
//处理接口参数上的注解,留给子类实现
isHttpAnnotation = processAnnotationsOnParameter(data, parameterAnnotations[i], i);
}
if (isHttpAnnotation) {data.ignoreParamater(i); }
//参数类型是否是URI,有了就使用,没有就使用默认的
if (parameterTypes[i] == URI.class) {
data.urlIndex(i);
} else if (!isHttpAnnotation && parameterTypes[i] != Request.Options.class) {
//请求体的校验:bodyIndex和bodyType只能设置一次,就非http和Options类型的参数只能存在一个
if (data.isAlreadyProcessed(i)) {
checkState(data.formParams().isEmpty() || data.bodyIndex() == null,"Body parameters cannot be used with form parameters.%s", data.warnings());
} else {
checkState(data.formParams().isEmpty(),"Body parameters cannot be used with form parameters.%s", data.warnings());
checkState(data.bodyIndex() == null,"Method has too many Body parameters: %s%s", method, data.warnings());
data.bodyIndex(i);
data.bodyType(Types.resolve(targetType, targetType, genericParameterTypes[i]));
}
}
}
//headerMap和queryMap进行Ma类型的校验
if (data.headerMapIndex() != null) {
checkMapString("HeaderMap", parameterTypes[data.headerMapIndex()],
genericParameterTypes[data.headerMapIndex()]);
}
if (data.queryMapIndex() != null) {
if (Map.class.isAssignableFrom(parameterTypes[data.queryMapIndex()])) {
checkMapKeys("QueryMap", genericParameterTypes[data.queryMapIndex()]);
}
}
return data;
}
}
4.4.3.3 SpringMvcContract
@Bean
@ConditionalOnMissingBean
public Contract feignContract(ConversionService feignConversionService) {
return new SpringMvcContract(this.parameterProcessors, feignConversionService);
}
* 构造参数值
①List<AnnotatedParameterProcessor>:参数注解的处理器,如下
//MatrixVariable 注解
annotatedArgumentResolvers.add(new MatrixVariableParameterProcessor());
//PathVariable 注解
annotatedArgumentResolvers.add(new PathVariableParameterProcessor());
//RequestParam 注解
annotatedArgumentResolvers.add(new RequestParamParameterProcessor());
//RequestHeader 注解
annotatedArgumentResolvers.add(new RequestHeaderParameterProcessor());
//SpringQueryMap 注解
annotatedArgumentResolvers.add(new QueryMapParameterProcessor());
//RequestPart 注解
annotatedArgumentResolvers.add(new RequestPartParameterProcessor());
②ConversionService feignConversionService:默认为DefaultFormattingConversionService,进行类型转换
* 重写和实现抽象方法
①重写核心方法parseAndValidateMetadata
- 先调用父类parseAndValidateMetadata,这里面也会回调这边的抽象子类实现
- 如果存在类上的@RequestMapping,在方法注解解析后没有设置ACCEPT\CONTENT_TYPE时,调用parseProduces和parseConsumes设置,即使用父类的设置
- 如果存在类上的@RequestMapping,调用parseHeaders设置请求头
②实现抽象方法processAnnotationOnClass处理接口(包括父接口)上的注解
获取RequestMapping的value,作为MethodMetadata中RequestTemplate的uri
data.template().uri(pathValue);
③实现抽象方法processAnnotationOnMethod处理接口方法的每一个方法上注解的解析
- 获取RequestMapping注解,取http访问方法(只能有一个)执行data.template().method(),和url(追加类上的)执行data.template().uri(pathValue, true);
- 调用parseProduces/parseConsumes/parseHeaders方法,取produces/consumes/headers属性作为RequestTemplate的ACCEP/CONTENT_TYPE/请求头
④实现抽象方法processAnnotationsOnParameter判断参数,以判断是否为http相关注解的标志
- 遍历一个参数的所有注解,调用对应的处理类进行处理,设置是否为http相关注解的标志下, 其中也会处理一些data.template().xxx的值
- 如下解析器对应的注解均是isHttpAnnotation = true
* PathVariableParameterProcessor:
获取@PathVariable注解上的name值,执行AnnotatedParameterContext.setParameterName(name),会data.indexToName().put(i, names);
data.template().queries()和headers()不存在此name时,执行data.formParams().add(name);
* QueryMapParameterProcessor
获取第一个标注了@SpringQueryMap注解的参数,执行metadata.queryMapIndex(paramIndex);
* RequestHeaderParameterProcessor
获取@RequestHeader注解上的参数且为Map,data.headerMapIndex(parameterIndex);
否则,获取注解上的name值,执行AnnotatedParameterContext.setParameterName(name),会data.indexToName().put(i, names)、data.template().header(name, value);
* RequestParamParameterProcessor
获取@RequestParam注解上的参数且为Map,data.headerMapIndex(parameterIndex);
否则,获取注解上的name值,执行AnnotatedParameterContext.setParameterName(name),会data.indexToName().put(i, names)、data.template().query(name, value);
value从data.template().queries()获取
- 如果isHttpAnnotation = true && data.indexToExpander().get(paramIndex) == null
获取此参数类型转为字符串的转换器,如果有,设置到indexToExpander
public class SpringMvcContract extends Contract.BaseContractimplements ResourceLoaderAware {
private static final String ACCEPT = "Accept";
private static final String CONTENT_TYPE = "Content-Type";
private static final TypeDescriptor STRING_TYPE_DESCRIPTOR = TypeDescriptor.valueOf(String.class);
private final Map<Class<? extends Annotation>, AnnotatedParameterProcessor> annotatedArgumentProcessors;
private final Map<String, Method> processedMethods = new HashMap<>();
private final ConversionService conversionService;
private final ConvertingExpanderFactory convertingExpanderFactory;
//略
public SpringMvcContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors,
ConversionService conversionService) {
List<AnnotatedParameterProcessor> processors;
if (!annotatedParameterProcessors.isEmpty()) {
processors = new ArrayList<>(annotatedParameterProcessors);
}
else {
processors = getDefaultAnnotatedArgumentsProcessors();
}
//注解类型和处理器的映射
this.annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
//这两个是类型转换相关
this.conversionService = conversionService;
//借助conversionService把值转为字符串类型
this.convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
}
//
@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
if (clz.getInterfaces().length == 0) {
RequestMapping classAnnotation = findMergedAnnotation(clz,RequestMapping.class);
if (classAnnotation != null) {
if (classAnnotation.value().length > 0) {
String pathValue = emptyToNull(classAnnotation.value()[0]);
pathValue = resolve(pathValue);
if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().uri(pathValue);
}
}
}
}
//重写接口核心类
//1、使用父类parseAndValidateMetadata,这里面也会回调这边的抽象子类实现
//2、如果存在类上的RequestMapping,
// - MethodMetadata中RequestTemplate的ACCEPT\CONTENT_TYPE,再解析方法注解后没有设置时,调用parseProduces和parseConsumes设置,即使用父类的设置
// - 调用parseHeaders设置请求头
@Override
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
this.processedMethods.put(Feign.configKey(targetType, method), method);
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
RequestMapping classAnnotation = findMergedAnnotation(targetType,RequestMapping.class);
if (classAnnotation != null) {
if (!md.template().headers().containsKey(ACCEPT)) {
parseProduces(md, method, classAnnotation);
}
if (!md.template().headers().containsKey(CONTENT_TYPE)) {
parseConsumes(md, method, classAnnotation);
}
parseHeaders(md, method, classAnnotation);
}
return md;
}
//处理方法上的注解
//获取RequestMapping注解,取http访问方法(只能有一个),和url(覆盖类上的)
//parseProduces(data, method, methodMapping,取produces属性作为RequestTemplate的ACCEP
//parseConsumes(data, method, methodMapping);取consumes属性作为RequestTemplate的CONTENT_TYPE
//parseHeaders(data, method, methodMapping);取headers属性作为RequestTemplate的请求头
@Override
protected void processAnnotationOnMethod(MethodMetadata data,
Annotation methodAnnotation, Method method) {
if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation
.annotationType().isAnnotationPresent(RequestMapping.class)) {
return;
}
RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
// HTTP Method
RequestMethod[] methods = methodMapping.method();
if (methods.length == 0) {
methods = new RequestMethod[] { RequestMethod.GET };
}
checkOne(method, methods, "method");
data.template().method(Request.HttpMethod.valueOf(methods[0].name()));
// path
checkAtMostOne(method, methodMapping.value(), "value");
if (methodMapping.value().length > 0) {
String pathValue = emptyToNull(methodMapping.value()[0]);
if (pathValue != null) {
pathValue = resolve(pathValue);
// Append path from @RequestMapping if value is present on method
if (!pathValue.startsWith("/") && !data.template().path().endsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().uri(pathValue, true);
}
}
// produces
parseProduces(data, method, methodMapping);
parseConsumes(data, method, methodMapping);
parseHeaders(data, method, methodMapping);
data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
}
private String resolve(String value) {
if (StringUtils.hasText(value)
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
.resolvePlaceholders(value);
}
return value;
}
//处理参数上的注解
@Override
protected boolean processAnnotationsOnParameter(MethodMetadata data,
Annotation[] annotations, int paramIndex) {
boolean isHttpAnnotation = false;
//简单封装了MethodMetadata和parameterIndex;
AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(data, paramIndex);
Method method = this.processedMethods.get(data.configKey());
//遍历一个参数的所有注解,调用对应的处理类进行处理
for (Annotation parameterAnnotation : annotations) {
AnnotatedParameterProcessor processor = this.annotatedArgumentProcessors.get(parameterAnnotation.annotationType());
if (processor != null) {
Annotation processParameterAnnotation;
processParameterAnnotation = synthesizeWithMethodParameterNameAsFallbackValue(
parameterAnnotation, method, paramIndex);
isHttpAnnotation |= processor.processArgument(context,processParameterAnnotation, method);
}
}
//获取此参数类型转为字符串的转换器,如果有,设置到indexToExpander
if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) {
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
if (this.conversionService.canConvert(typeDescriptor,STRING_TYPE_DESCRIPTOR)) {
Param.Expander expander = this.convertingExpanderFactory
.getExpander(typeDescriptor);
if (expander != null) {
data.indexToExpander().put(paramIndex, expander);
}
}
}
return isHttpAnnotation;
}
//略
}
5、代理增强SynchronousMethodHandler.invoke
5.1 invoke整体流程
* 基于buildTemplateFromArgs获取RequestTemplate, template = buildTemplateFromArgs.create(实际方法参数);
RequestTemplate里面翻转好了http调用所有的东西,包括访问方法、请求体等
* 获取Options类型的参数、重试器(默认为Retryer.NEVER_RETRY)
* 调用核心方法executeAndDecode(template, options)进行远程调用和响应处理
①先执行拦截器遍历调用interceptor.apply(template),是在容器中获取或者配置文件中指定的RequestInterceptor实现类
②调用HardCodedTarget(封装了客户端接口类型type、name、url属性).apply方法
- 如果RequestTemplate的url(例如从@RequestMapping获取的)不是以http开头,那么就需要使用HardCodedTarget里的url属性作为此RequestTemplate的host
RequestTemplate.target(url());,url()表时目标地址,在基于服务name访问时,此值为服务名称,调用target方法会处理RequestTemplate的target属性(拼接好的完整的路径)
- 再调用RequestTemplate.request()返回Request,封装了完整请求相关的信息,包括target + url(完整的或者从@RequestMapping获取的和@feignClient的path)等信息
③调用配置的客户端通信组件LoadBalancerFeignClient client.execute获取需要Response (流程见下)
IClientConfig requestConfig = getClientConfig(options, clientName); //clientName即为域名,服务名
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost); //this.delegate即为对应委托http客户端
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
最终回到FeignLoadBalancer的execute(RibbonRequest request, IClientConfig configOverride)进行通信,执行this.delegate的execute方法返回Response
此Response包含:int status;
private final String reason;
private final Map<String, Collection<String>> headers;
private final Body body; //响应流
private final Request request;
④处理返回值,默认处理完会关闭响应流,response.body()为网络输入流
- 如果返回值为Response类型,响应体长度超长(8192),直接返回,但是不关闭响应流;
否则,把响应转为字节数组,封装到一个新的Response(会复制原Response的this.status、reason、headers、body、request;),再返回给客户端
- 如果不为Response类型:code为200~300 :使用decoder对Response进行编码返回,decode(response);
code为404且返回类型不为void :使用decoder对Response进行编码返回;根据contentType把响应流的数据转为返回类型即可
其他直接抛出异常
⑤根据标识,关闭响应流
final class SynchronousMethodHandler implements MethodHandler {
private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
private final MethodMetadata metadata;
//HardCodedTarget(封装了客户端接口类型type、name、url属性)
private final Target<?> target;
//如下组件均从Builder中获取,
private final Client client;
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final Logger logger;
private final Logger.Level logLevel;
private final RequestTemplate.Factory buildTemplateFromArgs;
private final Options options;
private final Decoder decoder;
private final ErrorDecoder errorDecoder;
private final boolean decode404;
private final boolean closeAfterDecode;
private final ExceptionPropagationPolicy propagationPolicy;
private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
List<RequestInterceptor> requestInterceptors, Logger logger,
Logger.Level logLevel, MethodMetadata metadata,
RequestTemplate.Factory buildTemplateFromArgs, Options options,
Decoder decoder, ErrorDecoder errorDecoder, boolean decode404,
boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy) {
this.target = checkNotNull(target, "target");
this.client = checkNotNull(client, "client for %s", target);
this.retryer = checkNotNull(retryer, "retryer for %s", target);
this.requestInterceptors =
checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
this.logger = checkNotNull(logger, "logger for %s", target);
this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
this.metadata = checkNotNull(metadata, "metadata for %s", target);
this.buildTemplateFromArgs = checkNotNull(buildTemplateFromArgs, "metadata for %s", target);
this.options = checkNotNull(options, "options for %s", target);
this.errorDecoder = checkNotNull(errorDecoder, "errorDecoder for %s", target);
this.decoder = checkNotNull(decoder, "decoder for %s", target);
this.decode404 = decode404;
this.closeAfterDecode = closeAfterDecode;
this.propagationPolicy = propagationPolicy;
}
@Override
public Object invoke(Object[] argv) throws Throwable {
//获取RequestTemplate,里面翻转好了http调用所有的东西,包括访问方法、请求体等
RequestTemplate template = buildTemplateFromArgs.create(argv);
//获取Options类型的参数
Options options = findOptions(argv);
//重试器,默认为Retryer.NEVER_RETRY
Retryer retryer = this.retryer.clone();
while (true) {
try {
//核心方法
return executeAndDecode(template, options);
} catch (RetryableException e) {
try {
//默认为抛出异常,则会打破循环,无法重试
retryer.continueOrPropagate(e);
} catch (RetryableException th) {
Throwable cause = th.getCause();
if (propagationPolicy == UNWRAP && cause != null) { throw cause;
} else {throw th;}
}
continue;
}
}
}
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
//先执行拦截器遍历调用interceptor.apply(template)
//调用HardCodedTarget(封装了客户端接口类型type、name、url属性).apply方法
// 这里会再次RequestTemplate.target(url()),因为拦截器可以会对url进行修改
// 再调用RequestTemplate.request()返回Request,封装了请求相关的信息
Request request = targetRequest(template);
Response response;
long start = System.nanoTime();
try {
//核心方法:调用配置的客户端通信组件client.execute
response = client.execute(request, options);
} catch (IOException e) {
throw errorExecuting(request, e);
}
//处理返回值,默认处理完会关闭响应流
boolean shouldClose = true;
try {
//如果返回值为Response类型,response.body()为网络输入流
if (Response.class == metadata.returnType()) {
//响应体长度超长(8192),直接返回,但是不关闭响应流
if (response.body() == null) {
return response;
}
if (response.body().length() == null || response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
return response;
}
//把响应转为字节数组,封装到一个新的Response,再返回给客户端
byte[] bodyData = Util.toByteArray(response.body().asInputStream());
return response.toBuilder().body(bodyData).build();
}
//如果不为Response类型
// 1、code为200~300 :使用decoder对Response进行编码返回
// 2、code为404且返回类型不为void :使用decoder对Response进行编码返回
if (response.status() >= 200 && response.status() < 300) {
if (void.class == metadata.returnType()) {
return null;
} else {
//使用decoder对Response进行编码返回
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
}
} else if (decode404 && response.status() == 404 && void.class != metadata.returnType()) {
Object result = decode(response);
shouldClose = closeAfterDecode;
return result;
} else {
throw errorDecoder.decode(metadata.configKey(), response);
}
} catch (IOException e) {
throw errorReading(request, response, e);
} finally {
if (shouldClose) {
ensureClosed(response.body());
}
}
}
Request targetRequest(RequestTemplate template) {
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
return target.apply(template);
}
Object decode(Response response) throws Throwable {
try {
return decoder.decode(response, metadata.returnType());
} catch (FeignException e) {
throw e;
} catch (RuntimeException e) {
throw new DecodeException(response.status(), e.getMessage(), response.request(), e);
}
}
Options findOptions(Object[] argv) {
if (argv == null || argv.length == 0) {
return this.options;
}
return (Options) Stream.of(argv)
.filter(o -> o instanceof Options)
.findFirst()
.orElse(this.options);
}
}
5.2执行BuildTemplateByResolvingArgs获取RequestTemplate

* 在解析阶段就以及封装好每一个方法对应的BuildTemplateByResolvingArgs或子类
- 父类BuildTemplateByResolvingArgs
处理解析 RequestTemplate的整体流程,包含大部分的处理,例如对RequestTemplate进行url查询参数(@RequestParam)的拼接、请求头(@RequestHeader)的添加
路径参数的替换
- 子类BuildFormEncodedTemplateFromArgs
①基于解析阶段的md.bodyIndex(),例如feig接口方法中普通实体类的参数
使用编码器Encoder,默认为SpringEncoder,把bodyIndex对应的参数值转为请求体中contType指定的格式后,写入RequestTemplate的body
②接着执行父类的流程
- 子类BuildFormEncodedTemplateFromArgs
①从MethodMetadata.indexToName()中获取指定参数的名称和值的集合(包括别名)中过滤metadata.formParams()指定的那些值,封装为Map<String, ?> map
使用编码器Encoder,默认为SpringEncoder,把map转为请求体中contType指定的格式后,写入RequestTemplate的body
②接着执行父类的流程
for (MethodMetadata md : metadata) {
BuildTemplateByResolvingArgs buildTemplate;
if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {
buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
} else if (md.bodyIndex() != null) {
buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder, queryMapEncoder);
} else {
buildTemplate = new BuildTemplateByResolvingArgs(md, queryMapEncoder);
}
}
* 核心方法时工厂接口方法RequestTemplate create(Object[] argv),返回RequestTemplate
interface Factory {
RequestTemplate create(Object[] argv);
}
* BuildTemplateByResolvingArgs定义工厂的整体实现,create方法
①从之前解析的MethodMetadata中RequestTemplate基础上,创建新的RequestTemplate
会复制MethodMetadata里旧requestTemplate的target、fragment、uriTemplate、method、charset、body、decodeSlash、collectionFormat、queries、headers
②如果参数存在urlIndex,则使用实际参数的URL对象覆盖新RequestTemplate的mutable.target(模板路径)
③变量参数上下文的创建,Map<String, Object> varBuilder,value值会转为String类型
* 从MethodMetadata.indexToName()中获取指定参数的名称和值的集合(包括别名),使用indexToExpander映射为字符串(如果没有Expande,使用原值),
存到 Map<“名称”, 参数值> varBuilder,
* 这些参数是带有 @PathVariable(value = “名称”)、@RequestHeader(value = “名称”)、@RequestParam(value = “名称”)注解的
④底层调用RequestTemplate的resolve(variables)去解析参数值,使用RequestTemplate.resolve(variables),子类可重写
- 先执行子类覆盖的方法返回处理后的参数上下文variables,接着新的RequestTemplate的resolve(variables)方法
- 有基于此新RequestTemplate,在创建一个RequestTemplate副本
- 如果此RequestTemplate的queries查询参数变量不为空,使用参数上下文varBuilder进行表达式赋值,在拼接到url
例如@RequestParam标志的参数,在SpringMvcContract的静态解析阶段就会加入RequestTemplate的queries中,在运行阶段即③会把对应的实际参数值存于varBuilder
- 如果此的headers不为空,那么处理请求头,使用参数上下文进行表达式赋值,加入到RequestTemplate中
例如@RequestHeader标志的参数,和@RequestParam标志的处理类似处理RequestTemplate的heards中
- template的bodyTemplate如果存在的话,使用bodyTemplate.expand(variables)获取请求体(BuildEncodedTemplateFromArgs不会走这里)
⑤存在@RequestParam(参数类型为Map时)和SpringQueryMap注解时,获取Map对象属性名和值,再存到RequestTemplate的queries中
在后续的executeAndDecode方法,会把此queries中内容拼接到url上
⑥存在@RequestHeard(参数类型为Map时),获取Map对象属性名和值,存到RequestTemplate的headers
⑦返回此RequestTemplate
* BuildEncodedTemplateFromArgs继承BuildTemplateByResolvingArgs,重写了resolve方法,只增加处理RequestTemplate.body
①会使用编码组件SpringEncoder
- 根据请求contenType选择对应的请求编码处理,转为对应的格式后写入存入outputMessage(一个内存输出流中),在把此流数据RequestTemplate的Body中
- 例如时json的请求类型,就会选在messageConverters中选中FastJsonHttpMessageConverter作为转换器把原参数值转为json格式后,
HttpMessageConverter<Object> copy = (HttpMessageConverter<Object>) messageConverter;
copy.write(requestBody, requestContentType, outputMessage);
RequestTemplate.body(Request.Body.encoded(outputMessage.getOutputStream().toByteArray(), charset));//此时的bodyTemplate为null
②接着调用父类的super.resolve(argv, mutable, variables)--见上
* BuildFormEncodedTemplateFromArgs继承BuildTemplateByResolvingArgs,重写了resolve方法,只增加处理metadata.formParams()
①遍历父类传递的variables,如果存于metadata.formParams()中,会使用编码组件SpringEncoder进入处理后,加入RequestTemplate.body
②接着调用父类的super.resolve(argv, mutable, variables)--见上
private static class BuildTemplateByResolvingArgs implements RequestTemplate.Factory {
private final QueryMapEncoder queryMapEncoder;
protected final MethodMetadata metadata;
private final Map<Integer, Expander> indexToExpander = new LinkedHashMap<Integer, Expander>();
private BuildTemplateByResolvingArgs(MethodMetadata metadata, QueryMapEncoder queryMapEncoder) {
this.metadata = metadata;
this.queryMapEncoder = queryMapEncoder;
//indexToExpander收集每个参数值对应的字符转换器
//代码略
}
@Override
public RequestTemplate create(Object[] argv) {
//从之前解析的MethodMetadata中RequestTemplate基础上,创建新的RequestTemplate
//会复制旧requestTemplate的target、fragment、uriTemplate、method、charset、body、decodeSlash、collectionFormat、queries、headers
RequestTemplate mutable = RequestTemplate.from(metadata.template());
if (metadata.urlIndex() != null) {
int urlIndex = metadata.urlIndex();
checkArgument(argv[urlIndex] != null, "URI parameter %s was null", urlIndex);
//创建URI对象,并解析url的参数存到RequestTemplate的queries中
mutable.target(String.valueOf(argv[urlIndex]));
}
//参数上下文的创建
// 获取每个参数的名称集合(包括别名)和值,使用indexToExpander映射为字符串,存到 Map<String, Object> varBuilder
//即对于能够设置别名的注解,会在参数值上下文varBuilder中存在副本,比如/PathVariable、RequestParam、RequestHeader
Map<String, Object> varBuilder = new LinkedHashMap<String, Object>();
for (Entry<Integer, Collection<String>> entry : metadata.indexToName().entrySet()) {
int i = entry.getKey();
Object value = argv[entry.getKey()];
if (value != null) { // Null values are skipped.
if (indexToExpander.containsKey(i)) {
value = expandElements(indexToExpander.get(i), value);
}
for (String name : entry.getValue()) {
varBuilder.put(name, value);
}
}
}
//底层调用RequestTemplate的resolve(variables)去解析参数值,子类可重写,varBuilder存在方法参数和实际值
//1、处理url上的{}块,使用参数上下文进行表达式赋值
//2、拼接处理url查询参数queryString,使用参数上下文进行表达式赋值
//3、处理请求头,使用参数上下文进行表达式赋值
//4、template的bodyTemplate如果存在的话,直接把参数上下文写入请求体
RequestTemplate template = resolve(argv, mutable, varBuilder);
//存在@RequestParam(参数类型为Map时)和SpringQueryMap注解时,反射获取对象属性名和值拼接到url上,即存到RequestTemplate的queries中
if (metadata.queryMapIndex() != null) {
Object value = argv[metadata.queryMapIndex()];
Map<String, Object> queryMap = toQueryMap(value);
template = addQueryMapQueryParameters(queryMap, template);
}
//请求头对象的处理,存到RequestTemplate的headers
if (metadata.headerMapIndex() != null) {
template =
addHeaderMapHeaders((Map<String, Object>) argv[metadata.headerMapIndex()], template);
}
return template;
}
}
//只重写resolve方法
private static class BuildEncodedTemplateFromArgs extends BuildTemplateByResolvingArgs {
private final Encoder encoder;
private BuildEncodedTemplateFromArgs(MethodMetadata metadata, Encoder encoder,
QueryMapEncoder queryMapEncoder) {
super(metadata, queryMapEncoder);
this.encoder = encoder;
}
@Override
protected RequestTemplate resolve(Object[] argv,RequestTemplate mutable,Map<String, Object> variables) {
Object body = argv[metadata.bodyIndex()];
checkArgument(body != null, "Body parameter %s was null", metadata.bodyIndex());
try {
encoder.encode(body, metadata.bodyType(), mutable);
} catch (EncodeException e) {
throw e;
} catch (RuntimeException e) {
throw new EncodeException(e.getMessage(), e);
}
return super.resolve(argv, mutable, variables);
}
}
}
5.3 执行LoadBalancerFeignClient.execute进行负载均衡调用
5.3.1 概述
* Feign顶级接口Client
public interface Client {
Response execute(Request request, Options options) throws IOException;
}
* LoadBalancerFeignClient
顶层Client组件实现,在每一个单独name容器里是没有配置的,而存在于其父容器(Spring容器)中,
默认为LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);,其中参数均是从父容器注入,在 FeignRibbonClientAutoConfiguration中
①delegate为:内部委托的时机通信对象,比如ApacheHttpClient(也是顶层Client接口实现),适配底层的HttpClient(CloseableHttpClient)接口的实现类
②cachingFactory, clientFactory:创建Ribbon的工厂,见Spring Ribbon原理
* execute方法的实现流程
①从RequestTamplate中获取的Request中,创建URL,获取域名为服务名称,会基于此服务名称创建Ribbon的上下文
②从Ribbon工厂lbClientFactory中clientFactory获取IClientConfig,lbClient(clientName会调用lbClientFactory.create(clientName);
会创建org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer对象,这里就兼容了ribbon的功能了
③调用FeignLoadBalancer的executeWithLoadBalancer方法进行负载均衡且通信,获取响应对象Response返回
public class LoadBalancerFeignClient implements Client {
static final Request.Options DEFAULT_OPTIONS = new Request.Options();
//内部委托的时机通信对象,如okHttpClient
private final Client delegate;
//创建Ribbon的工厂
private CachingSpringLoadBalancerFactory lbClientFactory;
private SpringClientFactory clientFactory;
public LoadBalancerFeignClient(Client delegate,
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory) {
this.delegate = delegate;
this.lbClientFactory = lbClientFactory;
this.clientFactory = clientFactory;
}
@Override
public Response execute(Request request, Request.Options options) throws IOException {
try {
//创建URL,获取域名为服务名称,会基于此服务名称创建Ribbon的上下文
URI asUri = URI.create(request.url());
String clientName = asUri.getHost();
URI uriWithoutHost = cleanUrl(request.url(), clientName);
FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
this.delegate, request, uriWithoutHost);
//从Ribbon工厂中clientFactory获取IClientConfig
IClientConfig requestConfig = getClientConfig(options, clientName);
//通过SpringClientFactory创建基于Ribbon负载均衡的客户端FeignLoadBalancer,调用其executeWithLoadBalancer方法后获取响应对象Response
return lbClient(clientName).executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
}
catch (ClientException e) {
throw new RuntimeException(e);
}
}
IClientConfig getClientConfig(Request.Options options, String clientName) {
IClientConfig requestConfig;
if (options == DEFAULT_OPTIONS) {
requestConfig = this.clientFactory.getClientConfig(clientName);
}
else {
requestConfig = new FeignOptionsClientConfig(options);
}
return requestConfig;
}
private FeignLoadBalancer lbClient(String clientName) {
return this.lbClientFactory.create(clientName);
}
//略
}
5.3.2 FeignLoadBalance的创建

* LoadBalancerContext
底层封装了ILoadBalancer,主要提供例如基于ILoadBalancer选择服务实例方法、暴露记录服务状态的方法
* 基于SpringClientFactory 工厂创建FeignLoadBalancer
- SpringClientFactory是创建ribbon负载均衡功能的工厂,可以为当前clientName创建单独容器上下文,
可以获取ribbon的几个组件IClientConfig、IRule、IPing、ServerList<Server>、ServerListFilter<Server>、ILoadBalancer(Ribbon原理见上)
- 从Ribbon工厂中获取到IClientConfig、ILoadBalancer、ServerIntrospector后作为构造参数创建FeignLoadBalancer对象
new FeignLoadBalancer(ILoadBalancer , config, serverIntrospector),其中ILoadBalancer 的默认实现即为ZoneAwareLoadBalancer
public class CachingSpringLoadBalancerFactory {
protected final SpringClientFactory factory;
protected LoadBalancedRetryFactory loadBalancedRetryFactory = null;
private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
public CachingSpringLoadBalancerFactory(SpringClientFactory factory) {
this.factory = factory;
}
public CachingSpringLoadBalancerFactory(SpringClientFactory factory,
LoadBalancedRetryFactory loadBalancedRetryPolicyFactory) {
this.factory = factory;
this.loadBalancedRetryFactory = loadBalancedRetryPolicyFactory;
}
public FeignLoadBalancer create(String clientName) {
FeignLoadBalancer client = this.cache.get(clientName);
if (client != null) {
return client;
}
IClientConfig config = this.factory.getClientConfig(clientName);
ILoadBalancer lb = this.factory.getLoadBalancer(clientName);
ServerIntrospector serverIntrospector = this.factory.getInstance(clientName,
ServerIntrospector.class);
client = this.loadBalancedRetryFactory != null
? new RetryableFeignLoadBalancer(lb, config, serverIntrospector,
this.loadBalancedRetryFactory)
: new FeignLoadBalancer(lb, config, serverIntrospector);
this.cache.put(clientName, client);
return client;
}
}
5.3.3 FeignLoadBalance的executeWithLoadBalancer执行请求
基于LoadBalancerCommand实现这个流程:
* buildLoadBalancerComman方法:先创建LoadBalancerCommand,
①配置好LoadBalancerContext、RetryHandler、url
②其中RetryHandler会抽象子类实现:getRequestSpecificRetryHandler定制重试处理器获取
③使用抽象子类customizeLoadBalancerCommandBuilder定制customizeLoadBalancerCommandBuilder构造
④执行build进行创建LoadBalancerCommand
* 调用LoadBalancerCommand.submit处理整个流程,基于Observable
①触发ExecutionContextListenerInvoker监听器启动事件
②调用getServerFromLoadBalancer获取负载均衡后的服务实例(此方法封装于父类)
基于ILoadBalancer.chooseServer选择FeignLoadBalance
③再调用IClient接口的execute方法,例如FeignLoadBalance会实现这个方法
- 如果Feign配置了自己的超时时间,则优先时间,否则使用Ribbon配置的,存于IClientConfig中,
- 调用RibbonRequest.client()获取底层委托的HttpClient(从LoadBalancerFeignClient获取)的execute方法
- 返回响应RibbonResponse
④如果访问有异常,会基于retryHandler进行重试处,超过重试次数之后,直接抛出
注:调用流程的每个重要结点,例如请求完成后会调用LoadBalancerContext.noteRequestCompletion,会更新ILoadBalancer中服务的访问状态
//AbstractLoadBalancerAwareClient
public T executeWithLoadBalancer(final S request, final IClientConfig requestConfig) throws ClientException {
//创建LoadBalancerCommand,
//①配置好LoadBalancerContext、RetryHandler、url、手动指定Server
//②会暴露两个方法给子类实现:getRequestSpecificRetryHandler定制重试处理器、customizeLoadBalancerCommandBuilder定制customizeLoadBalancerCommandBuilder
LoadBalancerCommand<T> command = buildLoadBalancerCommand(request, requestConfig);
//开始进行负载均衡、和远程调用
try {
return command.submit(
new ServerOperation<T>() {
@Override
public Observable<T> call(Server server) {
URI finalUri = reconstructURIWithServer(server, request.getUri());
S requestForServer = (S) request.replaceUri(finalUri);
try {
//调用子类的execute,如FeignLoadBalancer的实现时,先优先使用Feign的超时功能,在调用底层委托的HttpCClient.execute
return Observable.just(AbstractLoadBalancerAwareClient.this.execute(requestForServer, requestConfig));
}
catch (Exception e) { return Observable.error(e);}
}
})
.toBlocking()
.single();
} catch (Exception e) {
Throwable t = e.getCause();
if (t instanceof ClientException) {throw (ClientException) t;
} else {throw new ClientException(e);}
}
}
public abstract RequestSpecificRetryHandler getRequestSpecificRetryHandler(S request, IClientConfig requestConfig);
protected LoadBalancerCommand<T> buildLoadBalancerCommand(final S request, final IClientConfig config) {
RequestSpecificRetryHandler handler = getRequestSpecificRetryHandler(request, config);
LoadBalancerCommand.Builder<T> builder = LoadBalancerCommand.<T>builder()
.withLoadBalancerContext(this)
.withRetryHandler(handler)
.withLoadBalancerURI(request.getUri());
customizeLoadBalancerCommandBuilder(request, config, builder);
return builder.build();
}
//LoadBalancerCommand
public Observable<T> submit(final ServerOperation<T> operation) {
//创建此次请求的执行上下文,封装了Server、serverAttemptCount、attemptCount = 0;
final ExecutionInfoContext context = new ExecutionInfoContext();
//监听器的触发
if (listenerInvoker != null) {
try {
listenerInvoker.onExecutionStart();
} catch (AbortExecutionException e) {
return Observable.error(e);
}
}
final int maxRetrysSame = retryHandler.getMaxRetriesOnSameServer();
final int maxRetrysNext = retryHandler.getMaxRetriesOnNextServer();
//selectServer方法:getServerFromLoadBalancer获取负载均衡后的服务实例(此方法封装于父类)
// 基于ILoadBalancer.chooseServer选择FeignLoadBalance
Observable<T> o =
(server == null ? selectServer() : Observable.just(server))
.concatMap(new Func1<Server, Observable<T>>() {
@Override
//修改IloadBalancer中此选定服务实例的状态,比如请求访问数、成功|失败数等
public Observable<T> call(Server server) {
context.setServer(server);
final ServerStats stats = loadBalancerContext.getServerStats(server);
// Called for each attempt and retry
Observable<T> o = Observable
.just(server)
.concatMap(new Func1<Server, Observable<T>>() {
@Override
public Observable<T> call(final Server server) {
context.incAttemptCount();
loadBalancerContext.noteOpenConnection(stats);
if (listenerInvoker != null) {
try {
listenerInvoker.onStartWithServer(context.toExecutionInfo());
} catch (AbortExecutionException e) {
return Observable.error(e);
}
}
final Stopwatch tracer = loadBalancerContext.getExecuteTracer().start();
//这里调用传递进来的operation,是执行对服务实例接口的访问,每个结点会记录服务实例的状态
return operation.call(server).doOnEach(new Observer<T>() {
private T entity;
@Override
public void onCompleted() {
recordStats(tracer, stats, entity, null);
}
@Override
public void onError(Throwable e) {
recordStats(tracer, stats, null, e);
if (listenerInvoker != null) {
listenerInvoker.onExceptionWithServer(e, context.toExecutionInfo());
}
}
@Override
public void onNext(T entity) {
this.entity = entity;
if (listenerInvoker != null) {
listenerInvoker.onExecutionSuccess(entity, context.toExecutionInfo());
}
}
private void recordStats(Stopwatch tracer, ServerStats stats, Object entity, Throwable exception) {
tracer.stop();
loadBalancerContext.noteRequestCompletion(stats, entity, exception, tracer.getDuration(TimeUnit.MILLISECONDS), retryHandler);
}
});
}
});
//如果出现异常,进行重试处理,FeignLoadBalance是默认不进行重试
if (maxRetrysSame > 0)
o = o.retry(retryPolicy(maxRetrysSame, true));
return o;
}
});
if (maxRetrysNext > 0 && server == null)
o = o.retry(retryPolicy(maxRetrysNext, false));
//重试还是异常的话,就抛出
return o.onErrorResumeNext(new Func1<Throwable, Observable<T>>() {
@Override
public Observable<T> call(Throwable e) {
if (listenerInvoker != null) {
listenerInvoker.onExecutionFailed(e, context.toFinalExecutionInfo());
}
return Observable.error(e);
}
});
}
5.3.4 FeignLoadBalance对重试处理的实现
* 创建RequestSpecificRetryHandle时,赋值给父类LoadBalancerContext的retryHandler变量
①若为非GET请求,okToRetryOnAllErrors为false
②其他情况一样:okToRetryOnConnectErrors为true、okToRetryOnAllErrors为true、retrySameServer取MaxAutoRetries、retryNextServer 取MaxAutoRetriesNextServer
* 在submit时
①如果已经获取到服务实例server,访问发送异常时判断retrySameServer大于0,会进行重试
②如果没有获取到服务实例server,发送异常时判断retryNextServer 大于0,会进行重试
@Override
public RequestSpecificRetryHandler getRequestSpecificRetryHandler(
RibbonRequest request, IClientConfig requestConfig) {
if (this.ribbon.isOkToRetryOnAllOperations()) {
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),requestConfig);
}
if (!request.toRequest().httpMethod().name().equals("GET")) {
return new RequestSpecificRetryHandler(true, false, this.getRetryHandler(),requestConfig);
}
else {
return new RequestSpecificRetryHandler(true, true, this.getRetryHandler(),requestConfig);
}
}
public RequestSpecificRetryHandler(boolean okToRetryOnConnectErrors, boolean okToRetryOnAllErrors, RetryHandler baseRetryHandler, @Nullable IClientConfig requestConfig) {
Preconditions.checkNotNull(baseRetryHandler);
this.okToRetryOnConnectErrors = okToRetryOnConnectErrors;
this.okToRetryOnAllErrors = okToRetryOnAllErrors;
this.fallback = baseRetryHandler;
if (requestConfig != null) {
if (requestConfig.containsProperty(CommonClientConfigKey.MaxAutoRetries)) {
retrySameServer = requestConfig.get(CommonClientConfigKey.MaxAutoRetries);
}
if (requestConfig.containsProperty(CommonClientConfigKey.MaxAutoRetriesNextServer)) {
retryNextServer = requestConfig.get(CommonClientConfigKey.MaxAutoRetriesNextServer);
}
}
}
6、feign整合Hystrix
6.1 配置
高版本的,需要如下配置,原先的feign.hystrix.enabled无效
* 配置
feign.circuitbreaker.enabled = true
* pom新增依赖
以新增CiruitBreaker实现类
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
* 使用如下配置
hystrix:
command:
default:
metrics:
rollingStats:
timeInMilliseconds: 5000
circuitBreaker:
requestVolumeThreshold: 2
errorThresholdPercentage: 50
sleepWindowInMilliseconds: 10000
6.2 源码
6.2.1 自动配置
Spring Cloud OpenFeign 配置之一 feign.circuitbreaker.enabled=true 开启 CircuitBreaker。直接看 feign 的配置类 FeignClientsConfiguration。
自动配置支持Hystrix的:
* Builder:FeignCircuitBreaker.builder()
* Target: FeignCircuitBreakerTarget,会封装好如下的CircuitBreakerFactory
* CircuitBreakerFactory实现类:HsytrixCircuitBreakerFactory,在spring-cloud-starter-netflix-hystrix新版本中
public class FeignClientsConfiguration {
......
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CircuitBreaker.class)
@ConditionalOnProperty("feign.circuitbreaker.enabled")
protected static class CircuitBreakerPresentFeignBuilderConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean({ Feign.Builder.class, CircuitBreakerFactory.class })
public Feign.Builder defaultFeignBuilder(Retryer retryer) {
return Feign.builder().retryer(retryer);
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnBean(CircuitBreakerFactory.class)
public Feign.Builder circuitBreakerFeignBuilder() {
return FeignCircuitBreaker.builder();
}
}
......
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Hystrix.class })
@ConditionalOnProperty(name = "spring.cloud.circuitbreaker.hystrix.enabled",
matchIfMissing = true)
public class HystrixCircuitBreakerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(CircuitBreakerFactory.class)
public CircuitBreakerFactory hystrixCircuitBreakerFactory() {
return new HystrixCircuitBreakerFactory();
}
.....
}
6.2.2 使用FeignCircuitBreake.Builder和target方法创建ReflectiveFeign
* 使用FeignCircuitBreaker.Builder收集配置的组件,他是Feign.Builder的子类
与常规的Targete相比,这个其中可以会指定FallbackFactory或者fallback
* 使用FeignCircuitBreakerTargete的target方法
- 如果配置FallbackFactory或者fallback,那么会使用FeignCircuitBreakerInvocationHandler覆盖Builder的invocationHandlerFactory (默认为InvocationHandlerFactory.Default()),
- 其中cretate的实现就是返回一个FeignCircuitBreakerInvocationHandler(默认的是返回FeignInvocationHandler)
super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(
circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
circuitBreakerGroupEnabled, circuitBreakerNameResolver));
* 调用Builder的newInstance生成ReflectiveFeign。
和常规的ReflectiveFeign相比,只是其中的InvocationHandlerFactory不一样,即代理增强不一样。
class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
......
@Override
public Object getObject() throws Exception {
return getTarget();
}
<T> T getTarget() {
......
return (T) loadBalance(builder, context,
new HardCodedTarget<>(this.type, this.name, this.url));
}
......
}
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,HardCodedTarget<T> target) {
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, target);
}
}
class FeignCircuitBreakerTargeter implements Targeter {
private final Map<String,Method> map = new HashMap<>();
private final CircuitBreakerFactory circuitBreakerFactory;
private final boolean circuitBreakerGroupEnabled;
private final CircuitBreakerNameResolver circuitBreakerNameResolver;
FeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, boolean circuitBreakerGroupEnabled, CircuitBreakerNameResolver circuitBreakerNameResolver) {
this.circuitBreakerFactory = circuitBreakerFactory;
this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
for (Method method : ReflectionUtils.getDeclaredMethods(FeignCircuitBreaker.Builder.class)) {
map.put(method.getName(),method);
}
}
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
Target.HardCodedTarget<T> target) {
if (!(feign instanceof FeignCircuitBreaker.Builder)) {
return feign.target(target);
}
FeignCircuitBreaker.Builder builder = (FeignCircuitBreaker.Builder) feign;
String name = !StringUtils.hasText(factory.getContextId()) ? factory.getName() : factory.getContextId();
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
return targetWithFallback(name, context, target, builder, fallback);
}
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
//获取指定的FallbackFactory,断路器工厂HsytrixCircuitBreakerFactory,最终创建ReflectiveFeign
return targetWithFallbackFactory(name, context, target, builder, fallbackFactory);
}
return builder(name, builder).target(target,new GlobalFallBackFactory<>(target));
}
private <T> T targetWithFallbackFactory(String feignClientName, FeignContext context,
Target.HardCodedTarget<T> target, FeignCircuitBreaker.Builder builder, Class<?> fallbackFactoryClass) {
FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>) getFromContext("fallbackFactory",
feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
//在FeignCircuitBreaker.Builder中设置下feignClientName和circuitBreakerFactory(容器中获取)
//最终创建ReflectiveFeign,其内设置 invocationHandlerFactory 为 FeignCircuitBreakerInvocationHandler
return builder(feignClientName, builder).target(target, fallbackFactory);
}
private <T> T targetWithFallback(String feignClientName, FeignContext context, Target.HardCodedTarget<T> target,
FeignCircuitBreaker.Builder builder, Class<?> fallback) {
T fallbackInstance = getFromContext("fallback", feignClientName, context, fallback, target.type());
return builder(feignClientName, builder).target(target, fallbackInstance);
}
//略
}
//重点在其Builder实现类
public final class FeignCircuitBreaker {
......
public static final class Builder extends Feign.Builder {
......
@Override
public <T> T target(Target<T> target) {
return build(null).newInstance(target);
}
@Override
public <T> T target(Target<T> target,FallbackFactory<?> fallbackFactory) {
return build(fallbackFactory).newInstance(target);
}
public Feign build(final FallbackFactory<?> nullableFallbackFactory) {
// 设置 invocationHandlerFactory 为 FeignCircuitBreakerInvocationHandler
super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(
circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
circuitBreakerGroupEnabled, circuitBreakerNameResolver));
return super.build();
}
}
}
6.2.3 使用FeignCircuitBreakerInvocationHandler创建Hystrix增强类
* 创建时机
- 在FeignCircuitBreakerTargeter的target方法创建代理中,就这种了代理增强类为FeignCircuitBreakerInvocationHandler
- 其中核心参数:
①target代理接口、dispatch为Map<String, MethodHandler>
②circuitBreakerFactory,由容器中获取,nullableFallbackFactory默认为null
super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(
circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
circuitBreakerGroupEnabled, circuitBreakerNameResolver));
* 增强的逻辑:
- 通过circuitBreakerNameResolver解析 feign 单个方法的keyName
比如Hystrx下的话,会是: 类名#方法名(参数类型)
- 通过获取CircuitBreaker工厂CircuitBreaker实例(见下节)
可通过HsytrixCircuitBreakerFactory.create(keyName)获取支持Hsytrix功能的CircuitBreaker
- 构建 circuitBreaker 执行的 supplier,里面封装了目标执行方法
里面执行的时: (Map<String, MethodHandler>)dispatch.get(method).invoke(args);
- 使用CircuitBreaker执行这个supplier
①nullableFallbackFactory不为null时,会生成函数对象fallback,届时会回调此fallback方法,执行CircuitBreaker.run(supplier,fallback)
即我们在@FeignClient中配置了fallback/fallbackFactory的情况会走此步骤
②nullableFallbackFactory为null时,直接CircuitBreaker.run(supplier)
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<Method, MethodHandler>();
List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
//...
//使用FeignCircuitBreakerInvocationHandler来创建Hystri支持的增强类
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;
}
//...
}
class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
......
@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
......
// 解析 feign 当个方法的key 类名#方法名(参数类型)
String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method);
// 通过获取CircuitBreaker工厂CircuitBreaker实例
// 可通过HsytrixCircuitBreakerFactory获取支持Hsytrix功能的CircuitBreaker
CircuitBreaker circuitBreaker = circuitBreakerGroupEnabled ? factory.create(circuitName, feignClientName)
: factory.create(circuitName);
// 构建 circuitBreaker 执行的 supplier,里面封装了目标执行方法
Supplier<Object> supplier = asSupplier(method, args);
// 设置 fallback
if (this.nullableFallbackFactory != null) {
Function<Throwable, Object> fallbackFunction = throwable -> {
Object fallback = this.nullableFallbackFactory.create(throwable);
try {
return this.fallbackMethodMap.get(method).invoke(fallback, args);
}
catch (Exception e) {
throw new IllegalStateException(e);
}
};
// 通过CircuitBreaker执行带有 fallback 的 supplier
return circuitBreaker.run(supplier, fallbackFunction);
}
// 执行 supplier
return circuitBreaker.run(supplier);
}
private Supplier<Object> asSupplier(final Method method, final Object[] args) {
// circuitBreaker 运行的时候会在另一个线程中,所以切换线程的时候同时切换上下文信息
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return () -> {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return dispatch.get(method).invoke(args);
}
catch (RuntimeException throwable) {
throw throwable;
}
catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
};
}
......
}
6.2.4 CircuitBreakerFactory工厂
6.2.4.1 AbstractCircuitBreakerFactory抽象类

* CircuitBreakerFactory抽象类
- 有两种:阻塞的和响应的
- create方法:用于返回具体的CircuitBreaker实现类,这时为了用户选择需要的熔断实现
比如resilience4j和Hystrix熔断,这里举例HystrixCircuitBreaker的
// 阻塞的
public abstract class CircuitBreakerFactory<CONF, CONFB extends ConfigBuilder<CONF>>
extends AbstractCircuitBreakerFactory<CONF, CONFB> {
public abstract CircuitBreaker create(String id);
public CircuitBreaker create(String id, String groupName) {
return create(id);
}
}
// reactive 的
public abstract class ReactiveCircuitBreakerFactory<CONF, CONFB extends ConfigBuilder<CONF>>
extends AbstractCircuitBreakerFactory<CONF, CONFB> {
public abstract ReactiveCircuitBreaker create(String id);
public ReactiveCircuitBreaker create(String id, String groupName) {
return create(id);
}
}
6.2.4.2 HystrixCircuitBreakerFactory实现类
* HystrixCommand.Setter配置setter的处理
- 可以通过工厂的configure方法基于Builder进行自定义配置。可以配置GroupKey、CommandKey、CommandPropertiesDefaults三个
- 如果没有局部的自定义,那么使用默认defaultConfiguration作为,这里也是需要通过工厂进行指定
如果没有指定,最终取默认配置:只有GroupKey = 类名 ,CommandKey为类名#方法名(参数类型)
* 核心方法create实现
直接new HystrixCircuitBreaker(setter);
public class HystrixCircuitBreakerFactory extends
CircuitBreakerFactory<HystrixCommand.Setter, org.springframework.cloud.netflix.hystrix.HystrixCircuitBreakerFactory.HystrixConfigBuilder> {
private Function<String, HystrixCommand.Setter> defaultConfiguration = id -> HystrixCommand.Setter
.withGroupKey(
HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName()))
.andCommandKey(HystrixCommandKey.Factory.asKey(id));
//配置全局默认的HystrixCommand.Setter
public void configureDefault(
Function<String, HystrixCommand.Setter> defaultConfiguration) {
this.defaultConfiguration = defaultConfiguration;
}
public HystrixConfigBuilder configBuilder(String id) {
return new HystrixCircuitBreakerFactory.HystrixConfigBuilder(id);
}
//用户可以调用工厂父类的configure,指定指定id设置自定义的HystrixCommand.Setter
// 此方法还会回调configBuilder方法。这里有内部实现类HystrixConfigBuilder
//没有就默认为defaultConfiguration。可通过configureDefault进行配置全局默认的HystrixCommand.Setter
public HystrixCircuitBreaker create(String id) {
HystrixCommand.Setter setter = getConfigurations().computeIfAbsent(id,
defaultConfiguration);
return new HystrixCircuitBreaker(setter);
}
public static class HystrixConfigBuilder
extends AbstractHystrixConfigBuilder<HystrixCommand.Setter> {
public HystrixConfigBuilder(String id) {
super(id);
}
@Override
public HystrixCommand.Setter build() {
return HystrixCommand.Setter.withGroupKey(getGroupKey())
.andCommandKey(getCommandKey())
.andCommandPropertiesDefaults(getCommandPropertiesSetter());
}
}
}
6.2.4.3 HystrixCircuitBreaker 实现类
public interface CircuitBreaker {
default <T> T run(Supplier<T> toRun) {
return run(toRun, throwable -> {
throw new NoFallbackAvailableException("No fallback available.", throwable);
});
};
<T> T run(Supplier<T> toRun, Function<Throwable, T> fallback);
}
* 通过HystrixCommand封装好配置类HystrixCommand.Setter,进行调用就可
* 其中实现run()为目标方法的调用
- HystrixCommand的run():调用就是原(Map<String, MethodHandler>)dispatch.get(method).invoke(args);
- HystrixCommand的getFallback():调用的就是封装了用户指定的fallbackFactory的apply方法
public class HystrixCircuitBreaker implements CircuitBreaker {
private HystrixCommand.Setter setter;
public HystrixCircuitBreaker(HystrixCommand.Setter setter) {
this.setter = setter;
}
@Override
public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
HystrixCommand<T> command = new HystrixCommand<T>(setter) {
@Override
protected T run() throws Exception {
return toRun.get();
}
@Override
protected T getFallback() {
return fallback.apply(getExecutionException());
}
};
return command.execute();
}
}
public abstract class HystrixCommand<R> extends AbstractCommand<R> implements HystrixExecutable<R>, HystrixInvokableInfo<R>, HystrixObservable<R> {
protected HystrixCommand(Setter setter) {
// use 'null' to specify use the default
this(setter.groupKey, setter.commandKey, setter.threadPoolKey, null, null, setter.commandPropertiesDefaults, setter.threadPoolPropertiesDefaults, null, null, null, null, null);
}
protected AbstractCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool,
HystrixCommandProperties.Setter commandPropertiesDefaults, HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults,
HystrixCommandMetrics metrics, TryableSemaphore fallbackSemaphore, TryableSemaphore executionSemaphore,
HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {
this.commandGroup = initGroupKey(group);
this.commandKey = initCommandKey(key, getClass());
//这里会从配置文件(远程)中获得相关的配置信息
this.properties = initCommandProperties(this.commandKey, propertiesStrategy, commandPropertiesDefaults);
this.threadPoolKey = initThreadPoolKey(threadPoolKey, this.commandGroup, this.properties.executionIsolationThreadPoolKeyOverride().get());
this.metrics = initMetrics(metrics, this.commandGroup, this.threadPoolKey, this.commandKey, this.properties);
this.circuitBreaker = initCircuitBreaker(this.properties.circuitBreakerEnabled().get(), circuitBreaker, this.commandGroup, this.commandKey, this.properties, this.metrics);
this.threadPool = initThreadPool(threadPool, this.threadPoolKey, threadPoolPropertiesDefaults);
//略
}
//略
}
更多推荐
所有评论(0)