等所有的 AnnotationConfigApplicationContext 子上下文 和 ApplicationContext 父上下文创建完成后,就进行 Feign 的自动化配置,
@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();
}
}
//other...
}
在 FeignAutoConfiguration 中会自动创建以下几个配置Bean:
- 注入所有的 FeignClientSpecification 配置类,供创建 FeignContext 使用;
- 如果容器中没有注册自定义的配置类,那么
configurations
将不包含 FeignClientSpecification 对象,否则会在setConfigurations
方法时进行默认配置类的替换,其实默认一定会有一个 FeignClientSpecification 对象,即 @EnableFeignClients 修饰的配置类。
- 如果容器中没有注册自定义的配置类,那么
- 创建 Targeter 配置Bean,默认使用 HystrixTargeter,供创建具体的实例对象使用。
Targeter是一个接口,它的target
方法会生成对应的实例对象。它有两个实现类,分别 DefaultTargeter 和 HystrixTargeter。而 OpenFeign 使用 HystrixTargeter 来封装关于 Hystrix 的实现。 DefaultTargeter 实现只是简单调用了 Feign.Builder 的 target
方法,并未实现 熔断 或 断路器 等功能:
class DefaultTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
return feign.target(target);
}
}
而对比 HystrixTargeter 的target
方法实现,它会根据 FeignClient 注解上的fallback
和 fallbackFactory
属性进行断路或者熔断:
class HystrixTargeter implements Targeter {
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
}
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName()
: factory.getContextId();
SetterFactory setterFactory = getOptional(name, context, SetterFactory.class);
if (setterFactory != null) {
builder.setterFactory(setterFactory);
}
//失败回调的Fallback
Class<?> fallback = factory.getFallback();
if (fallback != void.class) {
return targetWithFallback(name, context, target, builder, fallback);
}
//失败回调的FallbackFactory
Class<?> fallbackFactory = factory.getFallbackFactory();
if (fallbackFactory != void.class) {
return targetWithFallbackFactory(name, context, target, builder,
fallbackFactory);
}
//最后再调用Feign.Builder的target方法
return feign.target(target);
}
//other..
}
从上述代码中就能看到两者的区别,就不累赘了。
微信公众号:Java知识集训