服务发布注册的入口(@DubboComponentScan)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
我们看到了熟悉的东西:@Import(DubboComponentScanRegistrar.class) ,跟进去我们发现该类 实现了 ImportBeanDefinitionRegistrar 接口,该接口提供了类的注册的回调。也就是说DubboComponentScanRegistrar 最后会调用 registerBeanDefinitions 方法:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获取到元数据中配置的扫描路径,可以是多个,所以这里是集合
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 注册指定的bean
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 注册通用的bean
// @since 2.7.6 Register the common beans
registerCommonBeans(registry);
}
DubboComponentScanRegistrar#getPackagesToScan 这个方法中就是获取 DubboComponentScan 配置的参数,进行组装返回。
主要关注 DubboComponentScanRegistrar#registerServiceAnnotationBeanPostProcessor 方法:
private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 构建一个rootBeanDefinition
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
// 将前面组装的扫描路径作为一个属性放到 ServiceAnnotationBeanPostProcessor 中
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
//注册该Bean,毋庸置疑,这个Bean 就是 ServiceAnnotationBeanPostProcessor
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
可以看到,ServiceAnnotationBeanPostProcessor 被标记了过时,后续可能会有点变化。我们先来看一下 ServiceAnnotationBeanPostProcessor 的类图 :
从类图可以看出,在该Bean初始化前后,会调用好几个回调方法,其中 BeanDefinitionRegistryPostProcessor 就是Bean 注册后会调用一个 postProcessBeanDefinitionRegistry 方法,该方法在其父类中:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 注册一个监听器,这个是很关键的,等等需要去看这个类
// @since 2.7.5
registerBeans(registry, DubboBootstrapApplicationListener.class);
// 获取到那个扫描路径
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
// 进行扫描 DubboService 进行注入
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
然后我们重点看 ServiceClassPostProcessor#registerServiceBeans
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 注册一个扫描器
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
// Bean 名字解析相关
BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
// 通过注解过滤
// refactor @since 2.7.7
serviceAnnotationTypes.forEach(annotationType -> {
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
});
// 循环遍历我们配置的扫描路径
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)) {
// 遍历拼装好的 BeanDefinitionHolder
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
//注册Bean
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 + "]");
}
}
}
}
来看一下注解过滤中的serviceAnnotationTypes ,其实一目了然,DubboService 是新版的修改,避免与 Spring的 Service注解重名,org.apache.dubbo.config.annotation.Service 是兼容老版本,com.alibaba.dubbo.config.annotation.Service 也是为了兼容。
private final static List<Class<? extends Annotation>> serviceAnnotationTypes = asList(
// @since 2.7.7 Add the @DubboService , the issue : https://github.com/apache/dubbo/issues/6007
DubboService.class,
// @since 2.7.0 the substitute @com.alibaba.dubbo.config.annotation.Service
Service.class,
// @since 2.7.3 Add the compatibility for legacy Dubbo's @Service , the issue : https://github.com/apache/dubbo/issues/4330
com.alibaba.dubbo.config.annotation.Service.class
);
ServiceClassPostProcessor#registerServiceBean
主要功能:
- 服务以什么协议发布
- 服务的负载均衡策略
- 服务的容错策略
- 服务发布端口
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
// 获取到需要注册的Dubbo Service 的 bean class
Class<?> beanClass = resolveClass(beanDefinitionHolder);
// 获取都 Dubbo Service 的 注解元数据
Annotation service = findServiceAnnotation(beanClass);
/**
* The {@link AnnotationAttributes} of @Service annotation
* 获取到我们注解上面配置的参数信息
*/
AnnotationAttributes serviceAnnotationAttributes = getAnnotationAttributes(service, false, false);
// 获取该实现的接口
Class<?> interfaceClass = resolveServiceInterfaceClass(serviceAnnotationAttributes, beanClass);
// 获取实现类 类名
String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// 该方法主要是构建了一个ServiceBean
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
// ServiceBean Bean name
//获取类名,比如这里是 ServiceBean:com.demo.api.HelloService
String beanName = generateServiceBeanName(serviceAnnotationAttributes, interfaceClass);
if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
// 然后调用注册方法
registry.registerBeanDefinition(beanName, serviceBeanDefinition);
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?");
}
}
}
registry.registerBeanDefinition(beanName, serviceBeanDefinition); 最终通过上述代码,将一个 dubbo中提供的ServiceBean注入到Spring IOC容器。
ServiceBean的初始化阶段
public ServiceBean() {
super();
this.service = null;
}
当ServiceBean初始化完成之后,会调用下面的方法:
@Override
public void afterPropertiesSet() throws Exception {
if (StringUtils.isEmpty(getPath())) {
if (StringUtils.isNotEmpty(beanName)
&& StringUtils.isNotEmpty(getInterface())
&& beanName.startsWith(getInterface())) {
setPath(beanName);
}
}
}
源码跟到这里,我们应该知道,这里注册了一个 ServiceBean ,所以跟进这个类的构造,但是发现什么都没做,但是这个时候我们需要想起来,之前 ServiceClassPostProcessor#postProcessBeanDefinitionRegistry 方法内初始化了一个监听器 DubboBootstrapApplicationListener,我们看一下该监听器监听了什么:
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}
从这个代码可以看出,这个监听器必然执行,在 Spring 上下文刷新完毕的时候走 DubboBootstrapApplicationListener#onContextRefreshedEvent
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();
}
Dubbo 的初始化入口
- 元数据/远程配置信息的初始化
- 拼接url()
- 如果是dubbo协议,则启动netty server
- 服务注册