• Spring与Dubbo整合源码分析P2


    前言

    上篇文章中Spring与Dubbo整合源码分析-P1中介绍了EnbaleDubbo注解中的EnableDubboConfig注解,这个注解主要作用是在Spring容器初始化时将Dubbo服务相关的配置beanbeanDefinition注入到Spring容器中,将这些bean交由Spring进行管理,以便在合适的时机获取特定的bean实例。。这篇我们来详细了解一下DubboComponent注解的作用。

    问题

    DubboComponentScan注解的作用是啥?

    DubboComponentScan注解解析

    点开DubboComponentScan注解,如下所示:

    image-20220327161957558

    DubboComponentScan注解中使用了@import注解引入了DubboComponentScanRegistrarDubboComponentScanRegistrar实现了ImportBeanDefinitionRegistrar接口,可以向Spring容器中的beanDefinitionMap注册beanDefinition

    DubboComponentScanRegistrar

    DubboComponentScanRegistrar类的主要方法和注释如下:

    public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
          
            // 获取扫描路径
            Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
    
            // 将扫描路径下具备特定注解的类的beanDefinition注册到Sprin容器中
            registerServiceClassPostProcessor(packagesToScan, registry);
    
            // @since 2.7.6 Register the common beans
            // 注册基础组件
            registerCommonBeans(registry);
        }
    
        /**
         * Registers {@link ServiceClassPostProcessor}
         *
         * @param packagesToScan packages to scan without resolving placeholders
         * @param registry       {@link BeanDefinitionRegistry}
         * @since 2.5.8
         */
        private void registerServiceClassPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    
            // =========================重点===============================
            // 生成 ServiceClassPostProcessor 的 beanDefinition
            // ServiceClassPostProcessor用来处理特定注解,
            // 如 org.apache.dubbo.config.annotation.DubboService
            BeanDefinitionBuilder builder = rootBeanDefinition(ServiceClassPostProcessor.class);
            // =========================重点===============================
    
      
          
            // 设置扫描到包路径
            builder.addConstructorArgValue(packagesToScan);
            
            // 设置bean的角色
            builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
          
            // 获取beanDefinition
            AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
          
            // 注册
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
    
        }
    
      
        
      /**
    	 *  获取待扫描路径列表
    	 * @param metadata 注解的元数据信息
    	 * @return java.util.Set<java.lang.String> 待扫描路径列表
    	 */
        private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
          
            // 获取 DubboComponentScan注解上的键值对
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                    metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
          
          
            // 获取 key为basePackages的值
            String[] basePackages = attributes.getStringArray("basePackages");
          
            // 获取 key为value的值  其实就是上面的basePackages,只不过是别名
            String[] value = attributes.getStringArray("value");
          
            // 获取 key为basePackageClasses的值
            Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
            
          
            // Appends value array attributes
            Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
          
            packagesToScan.addAll(Arrays.asList(basePackages));
          
          
            // 遍历循环获取每个class所在的包路径
            for (Class<?> basePackageClass : basePackageClasses) {
                packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
            }
          
            // 如果packagesToScan还是为空,则获取启动类的包路径
            if (packagesToScan.isEmpty()) {
                return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
            }
          
            // 返回结果
            return packagesToScan;
        }
    
    }
    

    DubboComponentScanRegistrar类的方法都比较简单,只是向Spring容器中注册特定beanbeanDefinition,重点注意的是registerServiceClassPostProcessor这个方法,向Spring容器中注册了某些能够处理Dubbo注解的后置处理器,以便正常启动dubbo服务。

    ServiceClassPostProcessor

    ServiceClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,这样就可以对Spring容器中的某些beanDefinition进行特殊处理。

    image-20220327182959456

    ServiceClassPostProcessor类的主要方法和注释如下:

    public class ServiceClassPostProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware,
            ResourceLoaderAware, BeanClassLoaderAware {
    
        private static final List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
          
                // 三种不同的注解
                DubboService.class,
                org.apache.dubbo.config.annotation.Service.class,
                com.alibaba.dubbo.config.annotation.Service.class
        );
    
       
    
        protected final Set<String> packagesToScan;
    
    
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
            // 注册基础组件 DubboBootstrapApplicationListener
            // 这是个监听器,当spring容器发布ContextRefreshedEvent事件时,Dubbo就会触发监听逻辑
            registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
    
            // 获取待扫描路径set集合
            Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
    
            
            if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
              
                // 扫描包
                // 注册 被 @org.apache.dubbo.config.annotation.Service、@DubboService 或者 @com.alibaba.dubbo.config.annotation.Service 标记的bean
                registerServiceBeans(resolvedPackagesToScan, registry);
            } else {
                if (logger.isWarnEnabled()) {
                    logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
                }
            }
    
        }
    
        /**
         * 注册 被 @Service、@DubboService 或者 @com.alibaba.dubbo.config.annotation.Service 标记的     bean
         *
         * @param packagesToScan The base packages to scan
         * @param registry       {@link BeanDefinitionRegistry}
         */
        private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    
          
            // 构建 DubboClassPathBeanDefinitionScanner
            DubboClassPathBeanDefinitionScanner scanner =
                    new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
    
          
            // 获取 beanNameGenerator
            BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
    
            // 设置 beanNameGenerator
            scanner.setBeanNameGenerator(beanNameGenerator);
    
            // 添加过滤器
            serviceAnnotationTypes.forEach(annotationType -> {
                scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
            });
    
          
            // 遍历循环
            for (String packageToScan : packagesToScan) {
    
                // 扫描和实例化扫描路径下所有bean
                // 需要注意的是,Sprin中的scanner.scan不仅仅是扫描,还会去实例化被扫描到的bean
                scanner.scan(packageToScan);
    
                // 获取被 @org.apache.dubbo.config.annotation.Service、@DubboService 或者 @com.alibaba.dubbo.config.annotation.Service标注的beanDefinitionHolder集合
                Set<BeanDefinitionHolder> beanDefinitionHolders =
                        findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
    
                if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
    
                    // 遍历循环
                    for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                        // 注册ServiceBean
                        registerServiceBean(beanDefinitionHolder, registry, scanner);
                    }
    
                    if (logger.isInfoEnabled()) {
                        logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @DubboService Components { " +
                                beanDefinitionHolders +
                                " } were scanned under package[" + packageToScan + "]");
                    }
    
                } else {
    
                    if (logger.isWarnEnabled()) {
                        logger.warn("No Spring Bean annotating Dubbo's @DubboService was found under package["
                                + packageToScan + "]");
                    }
    
                }
    
            }
    
        }
    
      
    
    
        /**
         * Registers {@link ServiceBean} from new annotated {@link DubboService} {@link BeanDefinition}
         *
         * @param beanDefinitionHolder
         * @param registry
         * @param scanner
         * @see ServiceBean
         * @see BeanDefinition
         */
        private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
                                         DubboClassPathBeanDefinitionScanner scanner) {
    
            // 服务实现类
            Class<?> beanClass = resolveClass(beanDefinitionHolder);
    
            // 判断类上是否有DubboService Service 注解
            Annotation service = findServiceAnnotation(beanClass);
    
            // 获取注解元数据信息
            AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
    
            
            // 服务实现类实现的接口
            Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
    
            // 服务实现类对应的bean的名字
            String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
    
            // 构建 serviceBeanDefinition
            AbstractBeanDefinition serviceBeanDefinition =
                    buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
    
            // ServiceBean 的名称
            String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
    
            // 如果ServiceBean的beadDefinition没有被注册过
            if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { 
              
                // 注册ServiceBean的beadDefinition
                registry.registerBeanDefinition(beanName, serviceBeanDefinition);
              
                // ServiceBean的beadDefinition设置键值对
                if (!serviceBeanDefinition.getPropertyValues().contains("id")) {
                    serviceBeanDefinition.getPropertyValues().addPropertyValue("id", beanName);
                }
    
                if (logger.isInfoEnabled()) {
                    logger.info("The BeanDefinition[" + serviceBeanDefinition +
                            "] of ServiceBean has been registered with name : " + beanName);
                }
    
            } else {
    
                if (logger.isWarnEnabled()) {
                    logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition +
                            "] of ServiceBean[ bean name : " + beanName +
                            "] was be found , Did @DubboComponentScan scan to same package in many times?");
                }
    
            }
    
        }
    
        /**
         * 获取类上的@Service @DubboService 
         *
         * @param beanClass the {@link Class class} of Bean
         * @return <code>null</code> if not found
         * @since 2.7.3
         */
        private Annotation findServiceAnnotation(Class<?> beanClass) {
            return serviceAnnotationTypes
                    .stream()
                    .map(annotationType -> findMergedAnnotation(beanClass, annotationType))
                    .filter(Objects::nonNull)
                    .findFirst()
                    .orElse(null);
        }
    
        
        
        /**
         * 构建ServiceBean的BeanDefinition
         *
         * @param serviceAnnotation
         * @param serviceAnnotationAttributes
         * @param interfaceClass
         * @param annotatedServiceBeanName
         * @return
         * @since 2.7.3
         */
        private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
                                                                  AnnotationAttributes serviceAnnotationAttributes,
                                                                  Class<?> interfaceClass,
                                                                  String annotatedServiceBeanName) {
    
            // 构建 ServiceBean 的 beanDefinition
            BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
    
            AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    
          
          
            MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
    
          
          // 忽略掉一些属性,因为这些属性不能做简单的属性赋值,需要经过一些操作, 
          // 比如protocol这个是需要引用的是bean,而不是字符串,这里我们就要通过字符串去找到bean赋值
            String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol",
                    "interface", "interfaceName", "parameters");
    
            // 设置ServiceBean的属性值
            propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(serviceAnnotation, environment, ignoreAttributeNames));
    
            // ===========================重点=========================
            // 设置ServiceBean中的ref属性的值
            addPropertyReference(builder, "ref", annotatedServiceBeanName);
            // 设置ServiceBean中的interface属性的值
            builder.addPropertyValue("interface", interfaceClass.getName());
            // 设置ServiceBean中的parameters属性的值
            builder.addPropertyValue("parameters", DubboAnnotationUtils.convertParameters(serviceAnnotationAttributes.getStringArray("parameters")));
          
            // ====================================================
    
    
            // 下面都是ServiceBean的属性赋值 就不一一写了
           
            List<MethodConfig> methodConfigs = convertMethodConfigs(serviceAnnotationAttributes.get("methods"));
          
            // 设置ServiceBean中的methods属性的值
            if (!methodConfigs.isEmpty()) {
                builder.addPropertyValue("methods", methodConfigs);
            }
    
            /**
             * Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
             */
            String providerConfigBeanName = serviceAnnotationAttributes.getString("provider");
          
            if (StringUtils.hasText(providerConfigBeanName)) {
                addPropertyReference(builder, "provider", providerConfigBeanName);
            }
    
            /**
             * Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
             */
            String monitorConfigBeanName = serviceAnnotationAttributes.getString("monitor");
            if (StringUtils.hasText(monitorConfigBeanName)) {
                addPropertyReference(builder, "monitor", monitorConfigBeanName);
            }
    
            /**
             * Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
             */
            String applicationConfigBeanName = serviceAnnotationAttributes.getString("application");
            if (StringUtils.hasText(applicationConfigBeanName)) {
                addPropertyReference(builder, "application", applicationConfigBeanName);
            }
    
            /**
             * Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
             */
            String moduleConfigBeanName = serviceAnnotationAttributes.getString("module");
            if (StringUtils.hasText(moduleConfigBeanName)) {
                addPropertyReference(builder, "module", moduleConfigBeanName);
            }
    
    
            /**
             * Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference
             */
            String[] registryConfigBeanNames = serviceAnnotationAttributes.getStringArray("registry");
    
            List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
    
            if (!registryRuntimeBeanReferences.isEmpty()) {
                builder.addPropertyValue("registries", registryRuntimeBeanReferences);
            }
    
            /**
             * Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference
             */
            String[] protocolConfigBeanNames = serviceAnnotationAttributes.getStringArray("protocol");
    
            List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
    
            if (!protocolRuntimeBeanReferences.isEmpty()) {
                builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
            }
    
            return builder.getBeanDefinition();
    
        }
    }
    

    ServiceClassPostProcessor这个后置处理器主要是处理被@DubboService或者是com.alibaba.dubbo.config.annotation.Service注解的bean,利用Spring容器设置这些beanbeanDefinition的某些属性,然后再将bean实例化出来,留在后面使用。这里特别需要注意的一点是ServiceClassPostProcessor#postProcessBeanDefinitionRegistry这个方法会注册一个监听器,DubboBootstrapApplicationListener,而这个监听器是Dubbo服务导出的起点。这里先提一下,在后面Dubbo服务导出的文章会进行解释。

    debug过程

    DubboComponentScanRegistrar#registerServiceClassPostProcessor

    image-20220327201805928

    DubboComponentScanRegistrar#registerServiceClassPostProcessor

    image-20220327202002714

    ServiceClassPostProcessor

    postProcessBeanDefinitionRegistry

    image-20220327202203742

    registerServiceBeans

    image-20220327202307113

    registerServiceBean

    image-20220327202622703

    DefaultListableBeanFactory#registerBeanDefinition

    image-20220327202918534

    回答问题

    本章的问题是,DubboComponentScan注解的作用是啥?

    结合本章的内容,DubboComponentScan注解上使用了@Import注解引入了DubboComponentScanRegistrar。这个类的作用是向Spring容器中注册Dubbo服务中某些特定beanbeanDefinition将这些bean交由Spring进行管理以便在合适的时机获取特定的bean实例。同时在这个类中,registerServiceClassPostProcessor这个方法还会引入ServiceClassPostProcessor类,这个类的postProcessBeanDefinitionRegistry方法会向Spring容器注册被@DubboService@org.apache.dubbo.config.annotation.Service@com.alibaba.dubbo.config.annotation.Service标注的beanbeanDefinition将这些bean交由Spring进行管理以便在合适的时机获取特定的bean实例

    Reference

  • 相关阅读:
    $动态规划系列(1)——金矿模型的理解
    $Java HttpClient库的使用
    $Java-json系列(二):用JSONObject解析和处理json数据
    $百度应用引擎BAE的使用与应用部署
    利用ajax短轮询+php与服务器交互制作简易即时聊天网站
    MYSQL explain详解
    Redis 5种数据结构使用及注意事项
    Redis 存储机制
    memcache
    mysql分表和表分区详解
  • 原文地址:https://www.cnblogs.com/reecelin/p/16064379.html
Copyright © 2020-2023  润新知