1 注解定义
org.springframework.cloud
spring-cloud-starter-openfeign
2.2.5.RELEASE
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class>[] basePackageClasses() default {};
Class>[] defaultConfiguration() default {};
Class>[] clients() default {};
}
@EnableFeignClients注解告诉框架扫描所有使用注解@FeignClient定义的feign客户端,并把feign客户端注册到IOC容器中。
2 FeignClientsRegistrar
FeignClientsRegistrar通过实现ImportBeanDefinitionRegistrar接口,并结合@Import注解把bean注册到IOC容器中。
@Import注解使用方法可参见@Import注解。
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private ResourceLoader resourceLoader;
private Environment environment;
/*实现ResourceLoaderAware接口,可获取Spring中配置的加载程序(ResourceLoader),用于对资源进行访问;可用于访问类l类路径或文件资源*/
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/*实现EnvironmentAware接口,可以获取到系统的环境变量信息*/
public void setEnvironment(Environment environment) {
this.environment = environment;
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
this.registerDefaultConfiguration(metadata, registry);
this.registerFeignClients(metadata, registry);
}
}
3 registerDefaultConfiguration(metadata, registry)
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
/*获取当前类上@EnableFeignClients注解的所有属性*/
Map defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
/*name为"default.当前类的全路径(如果是内部类,则取外部类的全路径)"*/
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
} else {
name = "default." + metadata.getClassName();
}
/*注册bean,如下*/
this.registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
}
}
/*利用BeanDefinitionBuilder手动向IOC容器注入bean,类型是FeignClientSpecification*/
private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FeignClientSpecification.class);
/*设置FeignClientSpecification构造函数参数*/
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
/*例如:default.com.zhao.ProducerApplication.FeignClientSpecification*/
registry.registerBeanDefinition(name + "." + FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition());
}
4 registerFeignClients(metadata, registry)
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
scanner.setResourceLoader(this.resourceLoader);
Map attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
Class>[] clients = attrs == null ? null : (Class[])((Class[])attrs.get("clients"));
Object basePackages;
if (clients != null && clients.length != 0) {
final Set clientClasses = new HashSet();
basePackages = new HashSet();
Class[] var9 = clients;
int var10 = clients.length;
for(int var11 = 0; var11 < var10; ++var11) {
Class> clazz = var9[var11];
((Set)basePackages).add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
scanner.addIncludeFilter(new FeignClientsRegistrar.AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
} else {
scanner.addIncludeFilter(annotationTypeFilter);
basePackages = this.getBasePackages(metadata);
}
Iterator var17 = ((Set)basePackages).iterator();
while(var17.hasNext()) {
String basePackage = (String)var17.next();
Set candidateComponents = scanner.findCandidateComponents(basePackage);
Iterator var21 = candidateComponents.iterator();
while(var21.hasNext()) {
BeanDefinition candidateComponent = (BeanDefinition)var21.next();
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
Map attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = this.getClientName(attributes);
this.registerClientConfiguration(registry, name, attributes.get("configuration"));
this.registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
假定我们没配置@EnableFeignClients注解的clients属性
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
/*创建ClassPathScanningCandidateComponentProvider对象,通过后续的setResourceLoader和addIncludeFilter方法完成实例化*/
ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
scanner.setResourceLoader(this.resourceLoader);
/*获取当前类上@EnableFeignClients注解的所有属性*/
Map attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
/*在此处定义扫描带有@FeignClient注解的类*/
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
Class>[] clients = attrs == null ? null : (Class[])((Class[])attrs.get("clients"));
Object basePackages;
if (clients != null && clients.length != 0) {
......
} else {
/*赋值,扫描带有@FeignClient注解的类*/
scanner.addIncludeFilter(annotationTypeFilter);
/*获取当前类的包路径*/
basePackages = this.getBasePackages(metadata);
}
......
}
假定我们配置了@EnableFeignClients注解的clients属性
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
/*创建ClassPathScanningCandidateComponentProvider对象,通过后续的setResourceLoader和addIncludeFilter方法完成实例化*/
ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
scanner.setResourceLoader(this.resourceLoader);
/*获取当前类上@EnableFeignClients注解的所有属性*/
Map attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
Class>[] clients = attrs == null ? null : (Class[])((Class[])attrs.get("clients"));
Object basePackages;
if (clients != null && clients.length != 0) {
final Set clientClasses = new HashSet();
basePackages = new HashSet();
Class[] var9 = clients;
int var10 = clients.length;
/*循环配置的clients数组,client的包路径加入到basePackages中client的名称加入到clientClasses中*/
for(int var11 = 0; var11 < var10; ++var11) {
Class> clazz = var9[var11];
((Set)basePackages).add(ClassUtils.getPackageName(clazz));
clientClasses.add(clazz.getCanonicalName());
}
AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
protected boolean match(ClassMetadata metadata) {
String cleaned = metadata.getClassName().replaceAll("\\$", ".");
return clientClasses.contains(cleaned);
}
};
/*赋值,扫描带有@FeignClient注解的类和类名在clientClasses集合内的类(即clients属性配置的类)*/
scanner.addIncludeFilter(new FeignClientsRegistrar.AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
} else {
......
}
......
}
根据client属性是否配置,决定着basePackages扫描的包和scanner扫描规则,下面是统一处理逻辑
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
/*创建ClassPathScanningCandidateComponentProvider对象,通过后续的setResourceLoader和addIncludeFilter方法完成实例化*/
ClassPathScanningCandidateComponentProvider scanner = this.getScanner();
scanner.setResourceLoader(this.resourceLoader);
/*获取当前类上@EnableFeignClients注解的所有属性*/
Map attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(FeignClient.class);
Class>[] clients = attrs == null ? null : (Class[])((Class[])attrs.get("clients"));
Object basePackages;
if (clients != null && clients.length != 0) {
......
} else {
......
}
Iterator var17 = ((Set)basePackages).iterator();
/*循环basePackages*/
while(var17.hasNext()) {
String basePackage = (String)var17.next();
/*重要代码,扫描得到bean*/
Set candidateComponents = scanner.findCandidateComponents(basePackage);
Iterator var21 = candidateComponents.iterator();
/*循环bean*/
while(var21.hasNext()) {
BeanDefinition candidateComponent = (BeanDefinition)var21.next();
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition)candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
/*获取当前bean上@FeignClient注解的所有属性*/
Map attributes = annotationMetadata.getAnnotationAttributes(FeignClient.class.getCanonicalName());
/*获取client的name,依次取注解的contextId、value、name、serviceId值*/
String name = this.getClientName(attributes);
/*根据@FeignClient注解的configuration属性注册,前面已经介绍过了*/
this.registerClientConfiguration(registry, name, attributes.get("configuration"));
/*注册FeignClient,如下*/
this.registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
}
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) {
String className = annotationMetadata.getClassName();
/*利用BeanDefinitionBuilder手动向IOC容器注入bean,类型是FeignClientFactoryBean*/
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
this.validate(attributes);
/*设置FeignClientFactoryBean属性值*/
definition.addPropertyValue("url", this.getUrl(attributes));
definition.addPropertyValue("path", this.getPath(attributes));
String name = this.getName(attributes);
definition.addPropertyValue("name", name);
String contextId = this.getContextId(attributes);
definition.addPropertyValue("contextId", contextId);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(2);
String alias = contextId + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
beanDefinition.setAttribute("factoryBeanObjectType", className);
boolean primary = (Boolean)attributes.get("primary");
beanDefinition.setPrimary(primary);
String qualifier = this.getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
/*注册bean*/
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
/*注册bean和设置别名*/
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
5 扩展
FeignClientFactoryBean生成代理类