一.源码入口
1. 开启Feign客户端的核心注解为:@EnableFeignClients,表示该项目能够被声明为Feign的客户端
@Slf4j @SpringBootApplication @EnableDiscoveryClient @EnableFeignClientspublic class NnDataApplication { public static void main(String[] args) throws UnknownHostException { ConfigurableApplicationContext application = SpringApplication.run(NnDataApplication.class, args); }
2.@EnableFeignClients中的核心类是 FeignClientsRegistrar ,可以看到核心方法 registerBeanDefinitions()
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //2.1 注册Feign相关的配置 registerDefaultConfiguration(metadata, registry); //2.2 注册FeignClient对象 registerFeignClients(metadata, registry); }
2.1.将FeignClients的默认的配置属性封装成 FeignClientSpecification 的BeanDifinition对象
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //解析EnableFeignClients注解中的defaultAttrs默认属性,封装成Map 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(); } //注册FeignClientSpecification 的 BeanDifinition对象 registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration")); } }
2.2.解析指定路径(或默认路径下的)@FeignClient注解的属性和接口,将FeignClient对象封装成 FeignClientFactoryBean类的BeanDifinition对象,核心方法
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//获取类路径扫描器,作用是:扫描指定路径或者默认路径下的被@FeignClient注解修饰的接口以及@FeignClient中的属性 ClassPathScanningCandidateComponentProvider scanner = getScanner(); scanner.setResourceLoader(this.resourceLoader); //定义包扫描路径 Set<String> basePackages; //从@EnableFeignClient注解上获取所有的属性,封装成Map Map<String, Object> attrs = metadata .getAnnotationAttributes(EnableFeignClients.class.getName());
//注解过滤器,作用是,在扫描路径下 过滤出被@FeignClient修饰的接口 AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter( FeignClient.class);
//解析@EnableFeignClient中的clients属性(client属性主要是指定被@FeignClient修饰的类,指定该属性会覆盖包扫描路径下的被@FeignClient修饰的类) final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
//指定了clients属性 if (clients == null || clients.length == 0) { scanner.addIncludeFilter(annotationTypeFilter);
//从Map中 ,获取包路径 basePackages = getBasePackages(metadata); }
//没有指定clients属性 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))); } //遍历处理好的包路径集合 basePackages
for (String basePackage : basePackages) { Set<BeanDefinition> candidateComponents = scanner .findCandidateComponents(basePackage); for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { // verify annotated class is an interface 校验被@FeignClient修饰的类是否是接口 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()); //从属性中获取Client的名称 String name = getClientName(attributes);
//注册FeignClient中的配置信息,将配置信息注册为FeignClientSpecification 类型的BeanDifinition对象,参考2.1 registerClientConfiguration(registry, name, attributes.get("configuration")); //将 1.BeanDifinition注册器,2.包路径的元数据信息,3.@FeignClient中的属性的信息 通过registerFeignClient()方法注册为 FeignClientFactoryBean类的BeanDifinition对象 registerFeignClient(registry, annotationMetadata, attributes); } } } }
2.2.1.注册FeignClientFactoryBean的BD对象
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
//获取类名 String className = annotationMetadata.getClassName();
//构建 FeignClientFactoryBean对象,该对象实现了 Spring框架中的FactoryBean对象,在实例化时会调用getObject()方法将相关的对象注册到Spring容器中 BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes);
//将@FeignClient上的属性封装到BD对象中 definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); String name = getName(attributes); definition.addPropertyValue("name", name); String contextId = 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(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = contextId + "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; } BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); }
二.流程图:
链接: https://www.processon.com/view/link/61613dcc1efad41d824a3cef