【Feign】Feign源码分析(一): Feign配置类的BeanDifinition注册

一.源码入口

  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

原文地址:https://www.cnblogs.com/july-sunny/p/15478413.html