共计 2417 个字符,预计需要花费 7 分钟才能阅读完成。
明天咱们具体分析 FeignClientFactoryBean 的作用,剖析之前先贴出来 @EnableFeignClients 的局部细节:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {}
为什么要贴出 @EnableFeignClients 呢?因为这个 FeignClientsRegistrar 类是咱们解析 Feign 类的入口,上面的代码块是 FeignClientsRegistrar 的局部细节:
private void registerFeignClient(BeanDefinitionRegistry registry,
AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {String className = annotationMetadata.getClassName();
// 赋值 FeignClientFactoryBean 类
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
}
由下面的代码片段,能够看到 FeignClientsRegistrar 会解析 @EnableFeignClients 注解,而后在构建 BeanDefinition 过程中,会注入 FeignClientFactoryBean 类,这样一来在后续实例化咱们申明的 Feign 类型的 Bean 过程中,会依据咱们配置的 name/value,url 等信息,实例化适合的 FeignClient 类。
当初咱们大抵理解了 FeignClientFactoryBean 的作用。而后再看一下 FeignClientFactoryBean 的 getObject():
@Override
public Object getObject() throws Exception {FeignContext context = applicationContext.getBean(FeignContext.class);
Feign.Builder builder = feign(context);
// 如果咱们没有配置 url
if (!StringUtils.hasText(this.url)) {
String url;
if (!this.name.startsWith("http")) {url = "http://" + this.name;}
else {url = this.name;}
url += cleanPath();
// 调用负载平衡逻辑
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
this.name, url));
}
// 如果配置了 url
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) {
// not load balancing because we have a url,
// but ribbon is on the classpath, so unwrap
client = ((LoadBalancerFeignClient)client).getDelegate();}
builder.client(client);
}
Targeter targeter = get(context, Targeter.class);
// 底层会构建 HttpUrlConnection 对象,其实也就是一般的 http 申请
return targeter.target(this, builder, context, new HardCodedTarget<>(this.type, this.name, url));
}
当初有没有恍然大迷瞪?!这个 FeignClientFactoryBean 决定了要创立哪一种的 FeignClient 对象!
那么问题来了,FeignClientsRegistrar 类实现了 ImportBeanDefinitionRegistrar 接口,这个接口是干嘛用的呢?
图 1
1:注册 beanFactoy 处理器。
2:解析所有的 bean(ConfigurationClass)。
3:执行 FeignClientsRegistrar 类的 registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) 办法;
上面两个图是获取启动类中配置的注解信息,并且加载 springbean 容器中:因为咱们的启动类配置了 @EnableFeignClients,@EnableFeignClients 又引入了 FeignClientsRegistrar.class,所以此时会加载 FeignClientsRegistrar 类;
图 2
图 3
上面的代码块是具体调用的逻辑:
// 加载启动类的中注册器
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());