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

posted @ 2022-03-27 20:50  Reecelin  阅读(163)  评论(0编辑  收藏  举报