一、Dubbo服务注册成ServiceBean
通过注解来注册Dubbo服务的时候,在服务端和消费端都需要用到一个组件DubboComponentScanRegistrar,先看下registerBeanDefinitions()方法:
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 服务端服务注册
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 消费端服务注册
registerReferenceAnnotationBeanPostProcessor(registry);
}
DubboComponentScanRegistrar#registerServiceAnnotationBeanPostProcessor
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);
}
我们来看下 ServiceAnnotationBeanPostProcessor的继承关系:
看到这个继承关系,是不是很容易就联想到之前Mybatis源码分析中的MapperScannerConfigurer,没错确实有异曲同工之妙!
这个后置处理器会执行postProcessBeanDefinitionRegistry()方法,接着执行ServiceAnnotationBeanPostProcessor#registerServiceBeans()
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// Dubbo会创建自己的扫描器
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));
/**
* Add the compatibility for legacy Dubbo's @Service
*
* The issue : https://github.com/apache/dubbo/issues/4330
* @since 2.7.3
*/
scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class));
for (String packageToScan : packagesToScan) {
// Registers @Service Bean first
scanner.scan(packageToScan);
// Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
Set<BeanDefinitionHolder> beanDefinitionHolders =
findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
registerServiceBean(beanDefinitionHolder, registry, scanner);
}
if (logger.isInfoEnabled()) {
logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " +
beanDefinitionHolders +
" } were scanned under package[" + packageToScan + "]");
}
} else {
if (logger.isWarnEnabled()) {
logger.warn("No Spring Bean annotating Dubbo's @Service was found under package["
+ packageToScan + "]");
}
}
}
}
我们就来看下DubboClassPathBeanDefinitionScanner#doScan
public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 调用父类ClassPathBeanDefinitionScanner#doScan将被@Service(Dubbo)注解的类注入Spring IOC容器中
return super.doScan(basePackages);
}
ServiceAnnotationBeanPostProcessor#buildServiceBeanDefinition()方法中有个BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);进去看下:
public static BeanDefinitionBuilder rootBeanDefinition(Class<?> beanClass, String factoryMethodName) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
builder.beanDefinition = new RootBeanDefinition();
// 此处偷梁换柱把服务定义成ServiceBean.class!
builder.beanDefinition.setBeanClass(beanClass);
builder.beanDefinition.setFactoryMethodName(factoryMethodName);
return builder;
}
二 Dubbo服务暴露
上面的服务注册到Spring IOC容器每一个服务其实就是一个ServiceBean,ServiceBean 实现了 ApplicationListener,在 Spring 容器初始化的时候会调用 onApplicationEvent 方法。ServiceBean 重写了 onApplicationEvent 方法,实现了服务暴露的功能。
ServiceBean#onApplicationEvent
public void onApplicationEvent(ContextRefreshedEvent event) {
if (!isExported() && !isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
// 暴露服务
export();
}
}