zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    HDU 1016 Prime Ring Problem
    POJ 1724 ROADS(bfs最短路)
    HDU 1033 Edge
    IE 兼容模式
    HDU 1263 水果
    数据结构之图详解
    继续过中等难度.0309
    排序的稳定性
    Java+7入门经典
    哈希链表及其变种
  • 原文地址:https://www.cnblogs.com/july-sunny/p/15478413.html
Copyright © 2011-2022 走看看