1、@EnableFeignClients导入FeignClientsRegistrar
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
registerDefaultConfiguration(metadata, registry);// 注册默认配置FeignClientSpecification
registerFeignClients(metadata, registry);// 解析@FeignClient
}
2、解析@FeignClient
sequenceDiagram
org.springframework.cloud.openfeign.FeignClientsRegistrar ->> org.springframework.cloud.openfeign.FeignClientsRegistrar: registerFeignClient
org.springframework.cloud.openfeign.FeignClientsRegistrar->>org.springframework.cloud.openfeign.FeignClientFactoryBean: getObject,getTarget
org.springframework.cloud.openfeign.FeignClientFactoryBeanr-->>
HystrixTargeter: target->>feign.Feign.Builder#target(feign.Target<T>)
3、FeignAutoConfiguration中的feignContext包含feignClient的配置。
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext(); // 默认提供FeignClientsConfiguration
context.setConfigurations(this.configurations);
return context;
}
@Autowired(required = false)
private List<FeignClientSpecification> configurations = new ArrayList<>();
// FeignClientSpecification的bean会被注入。
4、FeignClientsConfiguration提供默认配置
Decoder:ResponseEntityDecoder
Encoder:SpringEncoder
Contract:SpringMvcContract
Retryer: Retryer.NEVER_RETRY
logger:Slf4jLogger
Feign.Builder: HystrixFeign.Builder
5、feignContext继承NamedContextFactory。通过name找到子context。
protected AnnotationConfigApplicationContext createContext(String name) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name)
.getConfiguration()) {
context.register(configuration);
}
}
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith("default.")) {
for (Class<?> configuration : entry.getValue().getConfiguration()) {
context.register(configuration);
}
}
}
context.register(PropertyPlaceholderAutoConfiguration.class,
this.defaultConfigType);
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
this.propertySourceName,
Collections.<String, Object>singletonMap(this.propertyName, name)));
if (this.parent != null) {
// Uses Environment from parent as well as beans
context.setParent(this.parent);
// jdk11 issue
// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
context.setClassLoader(this.parent.getClassLoader());
}
context.setDisplayName(generateDisplayName(name));
context.refresh();
return context;
}
6、接口调用分析同https://editor.csdn.net/md/?articleId=109299718。
spring cloud feign主要是通过ImportBeanDefinitionRegistrar(FeignClientsRegistrar)、FactoryBean(FeignClientFactoryBean)、NamedContextFactory(FeignContext)等扩展接口继承openfeign。
7、openfeign默认client使用HttpURLConnection。可通过引入ApacheHttpClient、OkHttpClient的依赖,替换默认的client。具体配置见org.springframework.cloud.openfeign.FeignAutoConfiguration.HttpClientFeignConfiguration、org.springframework.cloud.openfeign.FeignAutoConfiguration.OkHttpFeignConfiguration