按照以往的慣例,在研究源碼的時候,咱們先看一下spring.factories
文件下自動裝配的類FeignAutoConfiguration
,其中比較重要的東西有這麼幾個spring
@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環境,接下來也會提到@EnableFeignClients
註解解析查看完自動裝配的類,接着看@EnableFeignClients
註解ide
進入這個註解發現,它引入了配置類 FeignClientsRegistrar
,因爲這個類實現了ImportBeanDefinitionRegistrar
接口,因此按照咱們以往的經歷直接看一下registerBeanDefinitions
方法吧ui
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { registerDefaultConfiguration(metadata, registry); registerFeignClients(metadata, registry); }
這裏分爲了2步this
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客戶端持有的url
Feign
客戶端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個步驟:spa
ClassPathScanningCandidateComponentProvider
掃描全部的標註了@FeignClient
註解的接口@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的核心應該也在這個類裏面了
code