1.FeignClient生成代理过程
@EnableFeignClients注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public@interfaceEnableFeignClients
我们使用@EnableFeignClients来开启feign的功能。从源码中看,该注解主要作用是通过@Import注解引入FeignClientsRegistrar类,追踪源码。
注入类FeignClientsRegistrar.class
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware,BeanClassLoaderAware,EnvironmentAware
该接口实现了ResourceLoaderAware,BeanClassLoaderAware,EnvironmentAware接口,在解析@import注解的过程中会将感兴趣的bean注入到该类中,这里不详细展开。实现了ImportBeanDefinitionRegisterar接口,通过重写registerBeanDefinitions方法来注册默认的feign配置类和注册feignClients对应的FeignClientFactoryBean到容器当中。看一下源码:
主要的逻辑方法在下面这个方法:
@Override
Public void registerBeanDefinitions(AnnotationMetadatametadata,
BeanDefinitionRegistryregistry){
registerDefaultConfiguration(metadata,registry); // 注册@EnableFeignClients指定的默认配置类到容器
registerFeignClients(metadata,registry); //注册feignClients对应的feignClientFactoryBean到容器
}
// 注册默认的配置类(FeignClientSpecification)
Private void registerDefaultConfiguration(AnnotationMetadatametadata,
BeanDefinitionRegistryregistry){
Map<String,Object>defaultAttrs=metadata.getAnnotationAttributes(EnableFeignClients.class.getName(),true); // 获取默认的配置类
// 如果指定了配置类,对其进行注册
if(defaultAttrs!=null&&defaultAttrs.containsKey("defaultConfiguration")){
Stringname;
if(metadata.hasEnclosingClass()){
name="default."+metadata.getEnclosingClassName();
}
else{
name="default."+metadata.getClassName();
}
registerClientConfiguration(registry,name,
defaultAttrs.get("defaultConfiguration")); // 注册到容器
}
}
在registerFeignClients这个方法中,回去扫描所有带有FeignClient注解的类,遍历解析出所有带目标注解(@FeignClient)的beanDefinition,然后调用registerFeignClient生成一个代理类,实际上每一个client接口都会生成一个代理类
// 注册feignclients,实际上是其对应的工厂bean
Public void registerFeignClients(AnnotationMetadatametadata,
BeanDefinitionRegistryregistry){
ClassPathScanningCandidateComponentProviderscanner=getScanner();
scanner.setResourceLoader(this.resourceLoader);// 注解扫描器
…
AnnotationTypeFilter annotationTypeFilter=newAnnotationTypeFilter(
FeignClient.class);// 设置扫描的目标注解
…
省略一些代码,这里代码作用就是获取@EnableFeignClients的clients属性是否为空,确定扫描的基础包路径。(不为空时,基础包路径为指定clients class的所在包路径,为空时则为@EnableFeignClients所在包的路径)
…
for(String basePackage:basePackages){
// 解析出所有带目标注解(@FeignClient)的beanDefinition
Set<BeanDefinition>candidateComponents=scanner
.findCandidateComponents(basePackage);
// 遍历注册
for(BeanDefinition candidateComponent:candidateComponents){
if(candidateComponent instanceof AnnotatedBeanDefinition){
//verify annotated class is an interface //校验注解必须加载接口上
AnnotatedBeanDefinition beanDefinition=(AnnotatedBeanDefinition)candidateComponent;
AnnotationMetadata annotationMetadata=beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(),
"@FeignClient can only be specified on an interface");
Map<String,Object>attributes=annotationMetadata
.getAnnotationAttributes(
FeignClient.class.getCanonicalName());
String name=getClientName(attributes);
registerClientConfiguration(registry,name,
attributes.get("configuration")); // 注册指定的配置类
// 注册client(实际上为factoryBean)
registerFeignClient(registry,annotationMetadata,attributes);
}
}
}
}
主要来看一下registerFeignClient方法,为每一个BeanDefinition单独生成一个FeignClientFactoryBean,而FeignClientFactoryBean就是我们生成Feign接口代理类的关键
// 注册
Private void registerFeignClient(BeanDefinitionRegistryregistry,
AnnotationMetadataannotationMetadata,Map<String,Object>attributes){
StringclassName=annotationMetadata.getClassName();
// 构建FeignClientFactoryBean
BeanDefinitionBuilder definition=BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
validate(attributes);
definition.addPropertyValue("url",getUrl(attributes));
definition.addPropertyValue("path",getPath(attributes));
Stringname=getName(attributes);
definition.addPropertyValue("name",name);
definition.addPropertyValue("type",className);
definition.addPropertyValue("decode404",attributes.get("decode404"));
definition.addPropertyValue("fallback",attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory",attributes.get("fallbackFactory"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String alias=name+"FeignClient";
AbstractBeanDefinition beanDefinition=definition.getBeanDefinition();
Boolean primary=(Boolean)attributes.get("primary");//has a default,won't be null
beanDefinition.setPrimary(primary);
// 是否指定了别名
String qualifier=getQualifier(attributes);
if(StringUtils.hasText(qualifier)){
alias=qualifier;
}
BeanDefinitionHolderholder=new BeanDefinitionHolder(beanDefinition,className,
newString[]{alias});
// 注册factoryBean 和 别名
BeanDefinitionReaderUtils.registerBeanDefinition(holder,registry);
}
FeignClientFactoryBean类
FeignClientFactoryBean实现了FactoryBean,FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程。
springCloud FeignClient其实是利用了spring的代理工厂来生成代理类,所以这里将所有的 feignClient的描述信息 BeanDefinition设定为 FeignClientFactoryBean类型,该类又继承 FactoryBean,很明显,这是一个代理类。 在spring中, FactoryBean是一个工厂bean,用作创建代理bean,所以得出结论,feign将所有的feignClient bean包装成 FeignClientFactoryBean。扫描方法到此结束。
代理类什么时候会触发生成呢? 在spring刷新容器时,当实例化我们的业务service时,如果发现注册了FeignClient,spring就会去实例化该FeignClient,同时会进行判断是否是代理bean,如果为代理bean,则调用 FeignClientFactoryBean的 T getObject() throws Exception;方法生成代理bean。
Public Object getObject()throwsException{
// 获取feign的上下文
FeignContext context=(FeignContext)this.applicationContext.getBean(FeignContext.class);
Builder builder=this.feign(context); // 获取feign的建造者
String url;
if(!StringUtils.hasText(this.url)){ // 没有指定域名的,走服务发现
if(!this.name.startsWith("http")){
url="http://"+this.name;
}else{
url=this.name;
}
url=url+this.cleanPath();
// 返回生成的代理类(负载均衡的)
Return this.loadBalance(builder,context,newHardCodedTarget(this.type,this.name,url));
}else{
// 指定了域名的
if(StringUtils.hasText(this.url)&&!this.url.startsWith("http")){
this.url="http://"+this.url;
}
url=this.url+this.cleanPath();
//生成client
Client client=(Client)this.getOptional(context,Client.class);
if(client!=null){
//not lod balancing because we have a url,
//but ribbon is on the classpath,so unwrap // 因为指定了域名地址了所以不需要负载平衡走ribbon了
if(client instanceof LoadBalancerFeignClient){
client=((LoadBalancerFeignClient)client).getDelegate();
}
builder.client(client);
}
// 生成代理类
Targeter targeter=(Targeter)this.get(context,Targeter.class);
Return targeter.target(this,builder,context,new HardCodedTarget(this.type,this.name,url));
}
}
protected <T> T getOptional(FeignContext context, Class<T> type) {
return context.getInstance(this.contextId, type);
}
可以看到,最终是由FeignContext.getInstance来获取client
生成代理类则是通过
Return targeter.target(this,builder,context,new HardCodedTarget(this.type,this.name,url));
最终是由
@Override
public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
FeignContext context, Target.HardCodedTarget<T> target) {
return feign.target(target);
}
public <T> T target(Target<T> target) {
return this.build().newInstance(target);
}
public Feign build() {
Client client = (Client)Capability.enrich(this.client, this.capabilities);
Retryer retryer = (Retryer)Capability.enrich(this.retryer, this.capabilities);
List<RequestInterceptor> requestInterceptors = (List)this.requestInterceptors.stream().map((ri) -> {
return (RequestInterceptor)Capability.enrich(ri, this.capabilities);
}).collect(Collectors.toList());
Logger logger = (Logger)Capability.enrich(this.logger, this.capabilities);
Contract contract = (Contract)Capability.enrich(this.contract, this.capabilities);
Options options = (Options)Capability.enrich(this.options, this.capabilities);
Encoder encoder = (Encoder)Capability.enrich(this.encoder, this.capabilities);
Decoder decoder = (Decoder)Capability.enrich(this.decoder, this.capabilities);
InvocationHandlerFactory invocationHandlerFactory = (InvocationHandlerFactory)Capability.enrich(this.invocationHandlerFactory, this.capabilities);
QueryMapEncoder queryMapEncoder = (QueryMapEncoder)Capability.enrich(this.queryMapEncoder, this.capabilities);
Factory synchronousMethodHandlerFactory = new Factory(client, retryer, requestInterceptors, logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy, this.forceDecoding);
ParseHandlersByName handlersByName = new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
ReflectiveFeign中实现。
下面来看一下FeignContext
FeignContext是Feign的上下文对象
@Configuration
@ConditionalOnClass(Feign.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();
//将feign的配置类设置到feign的容器当中
context.setConfigurations(this.configurations);
return context;
}
}
可以看到feign的配置类设置到feign的容器当中,而集合中的元素 正是上面我们提到的两处调用 registerClientConfiguration方法添加进去的,前后呼应。
然而,当我们引入了 sleuth之后,获取的 feignContext确是 TraceFeignClientAutoConfiguration中配置的实例 sleuthFeignContext: