spring.factories
按照以往的惯例,在研究源码的时候,我们先看一下spring.factories
文件下自动装配的类FeignAutoConfiguration
,其中比较重要的东西有这么几个
@Autowired(required = false) private List<FeignClientSpecification> configurations = new ArrayList<>();
@Bean public FeignContext feignContext() { FeignContext context = new FeignContext(); context.setConfigurations(this.configurations); return context; }
@Configuration @ConditionalOnClass(name = "feign.hystrix.HystrixFeign") protected static class HystrixFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new HystrixTargeter(); } }
@Configuration @ConditionalOnMissingClass("feign.hystrix.HystrixFeign") protected static class DefaultFeignTargeterConfiguration { @Bean @ConditionalOnMissingBean public Targeter feignTargeter() { return new DefaultTargeter(); } }
- 属性
configurations
代表的是各个Feign客户端的配置类,这个稍后会再次提到 FeignContext
这个bean看名字就知道,Feign的上下文环境,包含了所有feign客户端的配置- 接下来是两个
Targeter
是看当前是否存在hystrix环境,接下来也会提到 - 除此之外这个类还包含了HttpClient相关的配置就不展开了
@EnableFeignClients
注解解析
查看完自动装配的类,接着看@EnableFeignClients
注解
进入这个注解发现,它引入了配置类 FeignClientsRegistrar
,由于这个类实现了ImportBeanDefinitionRegistrar
接口,所以按照我们以往的经历直接看一下registerBeanDefinitions
方法吧
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); registerFeignClients(metadata, registry); }
这里分为了2步
注册缺省配置
代码语言:javascript复制private void registerDefaultConfiguration(AnnotationMetadata metadata,BeanDefinitionRegistry registry) { // 获取注解@EnableFeignClients的注解属性 Map<String, Object> defaultAttrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName(), true);
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) { String name; if (metadata.hasEnclosingClass()) { name = "default." metadata.getEnclosingClassName(); } else {
name = "default." metadata.getClassName(); } // 各种信息准备就绪,现在执行注册 registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } } private void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) { BeanDefinitionBuilder builder = BeanDefinitionBuilder .genericBeanDefinition(FeignClientSpecification.class); builder.addConstructorArgValue(name); builder.addConstructorArgValue(configuration); registry.registerBeanDefinition( name "." FeignClientSpecification.class.getSimpleName(), builder.getBeanDefinition()); }
可以看到这里就是处理注册@EnableFeignClients
上defaultConfiguration属性所指定的客户端的缺省配置,注意这里配置都是注册为了FeignClientSpecification
类型的bean,这个类型的bean也是本文刚开始提到的被Feign上下文持有的各个Feign客户端持有的
注册各个Feign
客户端
代码语言:javascript复制public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader);
Set<String> basePackages;
Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName()); AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class); final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients"); if (clients == null || clients.length == 0) { scanner.addIncludeFilter(annotationTypeFilter); basePackages = getBasePackages(metadata); } else { final Set<String> clientClasses = new HashSet<>(); basePackages = new HashSet<>(); for (Class<?> clazz : clients) { basePackages.add(ClassUtils.getPackageName(clazz)); clientClasses.add(clazz.getCanonicalName()); } AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() { @Override protected boolean match(ClassMetadata metadata) { String cleaned = metadata.getClassName().replaceAll("\$", "."); return clientClasses.contains(cleaned); } }; scanner.addIncludeFilter( new AllTypeFilter(Arrays.asList(filter, annotationTypeFilter))); }
for (String basePackage : basePackages) { Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { 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<String, Object> attributes = annotationMetadata .getAnnotationAttributes( FeignClient.class.getCanonicalName());
String name = getClientName(attributes);
registerClientConfiguration(registry, name, attributes.get("configuration")); registerFeignClient(registry, annotationMetadata, attributes); } } }
这里一共分为3个步骤:
- 使用
ClassPathScanningCandidateComponentProvider
扫描所有的标注了@FeignClient
注解的接口 - 将注解上包含的属性作为bean注册,这些属性也就是每个Feign客户端端的配置
- 将
@Feign
客户端注册
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { // 1.获取标注@Feign注解的接口名称 String className = annotationMetadata.getClassName();
// 2.使用BeanDefinitionBuilder构造bean:FeignClientFactoryBean BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes);
// 3.添加FeignClientFactoryBean的各个属性 definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = 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);
// 4.设置别名 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; }
// 5.注册FeignClientFactoryBean BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);}
上方这个方法通过了5步把各个FeignClient都注册成了bean:FeignClientFactoryBean
,相信看过之前文章的同学都知道FactoryBean
系列的bean是干什么的了。而Feign整合Ribbon和Hystrix的核心应该也在这个类里面了