今天我们详细分析FeignClientFactoryBean的作用,贴出分析前@EnableFeignClients的一些细节:@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(FeignClientsRegistrar.class)public@interfaceEnableFeignClients{}为什么要发布@EnableFeignClients?因为这个FeignClientsRegistrar类是我们解析Feign类的入口,下面的代码块是FeignClientsRegistrar的部分细节:annotationMetadata.getClassName();//AssignFeignClientFactoryBeanclassBeanDefinitionBuilderdefinition=BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);}从上面的代码片段可以看出,FeignClientsRegistrar会解析@EnableFeignClients注解,然后在BeanDefinition的构造过程中注入FeignClientFactoryBean类,这样在后续实例化我们声明的Feign类型的Bean时,会根据我们配置的name/value、url等信息实例化相应的FeignClient类。现在我们对FeignClientFactoryBean的作用有了一个大概的了解。然后看一下FeignClientFactoryBean的getObject():@OverridepublicObjectgetObject()throwsException{FeignContextcontext=applicationContext.getBean(FeignContext.class);Feign.Builderbuilder=feign(上下文);//如果我们没有配置urlif(!StringUtils.hasText(this.url)){Stringurl;如果(!this.name.startsWith("http")){url="http://"+this.name;}else{网址=这个。姓名;}url+=cleanPath();//调用负载均衡逻辑returnloadBalance(builder,context,newHardCodedTarget<>(this.type,this.name,url));}//如果配置了urlif(StringUtils.hasText(this.url)&&!this.url.startsWith("http")){this.url="http://"+this.url;}字符串url=this.url+cleanPath();客户端client=getOptional(context,Client.claSS);if(client!=null){if(clientinstanceofLoadBalancerFeignClient){//没有负载平衡,因为我们有一个url,//但是ribbon在类路径上,所以打开client=((LoadBalancerFeignClient)client).getDelegate();}builder.client(客户端);}Targetertargeter=get(context,Targeter.class);//底层会构建HttpUrlConnection对象,其实就是一个普通的http请求returntargeter.target(this,builder,context,newHardCodedTarget<>(this.type,this.name,url));你现在惊呆了吗?!这个FeignClientFactoryBean决定了创建哪个FeignClient对象!那么问题来了,FeignClientsRegistrar类实现了ImportBeanDefinitionRegistrar接口。这个接口是做什么用的?图11:注册beanFactoy处理器2:解析所有beans(ConfigurationClass)。3:执行FeignClientsRegistrar类的registerBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry)方法;下面两张图是获取启动类中配置的注解信息加载到springbean容器中:因为我们的启动类配置了@EnableFeignClients,@EnableFeignClients也引入了FeignClientsRegistrar.class,所以FeignClientsRegistrar类会被加载到这次;图2和图3下方的代码块是具体调用的逻辑://加载启动类的中间寄存器loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
