明天咱们具体分析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());