序
本文主要研究一下 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