乐趣区

聊聊dubbo的DubboComponentScanRegistrar

本文主要研究一下 dubbo 的 DubboComponentScanRegistrar

DubboComponentScanRegistrar

dubbo-2.7.3/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrar.java

public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);

        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);

        registerReferenceAnnotationBeanPostProcessor(registry);

    }

    /**
     * Registers {@link ServiceAnnotationBeanPostProcessor}
     *
     * @param packagesToScan packages to scan without resolving placeholders
     * @param registry       {@link BeanDefinitionRegistry}
     * @since 2.5.8
     */
    private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
        builder.addConstructorArgValue(packagesToScan);
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);

    }

    /**
     * Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory}
     *
     * @param registry {@link BeanDefinitionRegistry}
     */
    private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {

        // Register @Reference Annotation Bean Processor
        BeanRegistrar.registerInfrastructureBean(registry,
                ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);

    }

    private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
        String[] value = attributes.getStringArray("value");
        // Appends value array attributes
        Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
        packagesToScan.addAll(Arrays.asList(basePackages));
        for (Class<?> basePackageClass : basePackageClasses) {packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
        }
        if (packagesToScan.isEmpty()) {return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
        }
        return packagesToScan;
    }

}
  • DubboComponentScanRegistrar 实现了 ImportBeanDefinitionRegistrar 接口定义的 registerBeanDefinitions 方法;它首先通过 getPackagesToScan 方法从 AnnotationMetadata 读取要扫描的包,然后再执行 registerServiceAnnotationBeanPostProcessor、registerReferenceAnnotationBeanPostProcessor 方法
  • getPackagesToScan 方法读取 DubboComponentScan 注解信息,获取要扫描的包;registerServiceAnnotationBeanPostProcessor 方法则是通过 BeanDefinitionReaderUtils.registerWithGeneratedName 注册 ServiceAnnotationBeanPostProcessor
  • registerReferenceAnnotationBeanPostProcessor 方法则是通过 BeanRegistrar.registerInfrastructureBean 注册 ReferenceAnnotationBeanPostProcessor

DubboComponentScanRegistrarTest

dubbo-2.7.3/dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/context/annotation/DubboComponentScanRegistrarTest.java

public class DubboComponentScanRegistrarTest {

    @BeforeEach
    public void setUp() {ConfigManager.getInstance().clear();}

    @AfterEach
    public void tearDown() {ConfigManager.getInstance().clear();}

    @Test
    public void test() {AnnotationConfigApplicationContext providerContext = new AnnotationConfigApplicationContext();

        providerContext.register(ProviderConfiguration.class);

        providerContext.refresh();

        DemoService demoService = providerContext.getBean(DemoService.class);

        String value = demoService.sayName("Mercy");

        Assertions.assertEquals("Hello,Mercy", value);

        Class<?> beanClass = AopUtils.getTargetClass(demoService);

        // DemoServiceImpl with @Transactional
        Assertions.assertEquals(DemoServiceImpl.class, beanClass);

        // Test @Transactional is present or not
        Assertions.assertNotNull(findAnnotation(beanClass, Transactional.class));

        AnnotationConfigApplicationContext consumerContext = new AnnotationConfigApplicationContext();

        consumerContext.register(ConsumerConfiguration.class);

        consumerContext.refresh();

        ConsumerConfiguration consumerConfiguration = consumerContext.getBean(ConsumerConfiguration.class);

        demoService = consumerConfiguration.getDemoService();

        value = demoService.sayName("Mercy");

        Assertions.assertEquals("Hello,Mercy", value);

        ConsumerConfiguration.Child child = consumerContext.getBean(ConsumerConfiguration.Child.class);

        // From Child

        demoService = child.getDemoServiceFromChild();

        Assertions.assertNotNull(demoService);

        value = demoService.sayName("Mercy");

        Assertions.assertEquals("Hello,Mercy", value);

        // From Parent

        demoService = child.getDemoServiceFromParent();

        Assertions.assertNotNull(demoService);

        value = demoService.sayName("Mercy");

        Assertions.assertEquals("Hello,Mercy", value);

        // From Ancestor

        demoService = child.getDemoServiceFromAncestor();

        Assertions.assertNotNull(demoService);

        value = demoService.sayName("Mercy");

        Assertions.assertEquals("Hello,Mercy", value);

        providerContext.close();
        consumerContext.close();}


}
  • DubboComponentScanRegistrarTest 分别验证了 providerContext、consumerContext

小结

  • DubboComponentScanRegistrar 实现了 ImportBeanDefinitionRegistrar 接口定义的 registerBeanDefinitions 方法;它首先通过 getPackagesToScan 方法从 AnnotationMetadata 读取要扫描的包,然后再执行 registerServiceAnnotationBeanPostProcessor、registerReferenceAnnotationBeanPostProcessor 方法
  • getPackagesToScan 方法读取 DubboComponentScan 注解信息,获取要扫描的包;registerServiceAnnotationBeanPostProcessor 方法则是通过 BeanDefinitionReaderUtils.registerWithGeneratedName 注册 ServiceAnnotationBeanPostProcessor
  • registerReferenceAnnotationBeanPostProcessor 方法则是通过 BeanRegistrar.registerInfrastructureBean 注册 ReferenceAnnotationBeanPostProcessor

doc

  • DubboComponentScanRegistrar
退出移动版