Dubbo服務注冊原理
文章目錄
- 1注冊步驟
- 2 猜想:
- 3源碼分析
-
- 3.1 @DubboComponentScan
-
- 3.1.1 圖片總結
- 3.2 DubboBootstrapApplicationListener.java
1注冊步驟
- 使用注解@DubboService或@Service
- 掃描注解@DubboComponentScan
2 猜想:
(1)掃描注解
(2)組裝url
(3)啟動服務(根據url中配置的協議、端口去發布對應的服務)
(4)注冊到注冊中心
3源碼分析
3.1 @DubboComponentScan
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({DubboComponentScanRegistrar.class})
public @interface DubboComponentScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
DubboComponentScanRegistrar:動態注冊bean到IOC中,但是是注冊哪個bean?需要分析下源碼
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//獲取@DubboComponentScan注解中配置的包路徑
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
//注冊bean到IOC容器中
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// @since 2.7.6 Register the common beans
registerCommonBeans(registry);
}
點擊 registerServiceAnnotationBeanPostProcessor(packagesToScan, registry),可以看到將ServiceAnnotationBeanPostProcessor加載到IOC容器中
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.java
public ServiceAnnotationBeanPostProcessor(Set<String> packagesToScan) {
super(packagesToScan);
}
點擊父類ServiceClassPostProcessor.java的構造器,在bean加載到IOC之后會觸發postProcessBeanDefinitionRegistry方法
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// @since 2.7.5
//注冊基礎bean
registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
//如果掃描的包路徑不為空,注冊服務bean:serviceBean
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
registerInfrastructureBean()方法中將DubboBootstrapApplicationListener注冊到容器中,
DubboBootstrapApplicationListener中的onApplicationContextEvent()方法會在spring 容器的上下文裝載完成之后,觸發監聽
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}
再來看下registerServiceBeans(resolvedPackagesToScan, registry) 代碼
掃描所有加了@DubboService或@Service注解的bean,但不是注冊到IOC容器里
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
DubboClassPathBeanDefinitionScanner scanner =
new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
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)) {
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 + "]");
}
}
}
}
點擊 registerServiceBean(beanDefinitionHolder, registry, scanner);
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
DubboClassPathBeanDefinitionScanner scanner) {
Class<?> beanClass = resolveClass(beanDefinitionHolder);
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();
AbstractBeanDefinition serviceBeanDefinition =
buildServiceBeanDefinition(service, serviceAnnotationAttributes, interfaceClass, annotatedServiceBeanName);
// ServiceBean Bean name
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?");
}
}
}
buildServiceBeanDefinition
private AbstractBeanDefinition buildServiceBeanDefinition(Annotation serviceAnnotation,
AnnotationAttributes serviceAnnotationAttributes,
Class<?> interfaceClass,
String annotatedServiceBeanName) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceBean.class);
//省略代碼
最終將org.apache.dubbo.config.spring.ServiceBean注冊到IOC容器中
3.1.1 圖片總結

3.2 DubboBootstrapApplicationListener.java
DubboBootstrapApplicationListener.java實現了監聽接口,最終會調用ServiceConfig#export()方法,調用過程如下圖:

浙公網安備 33010602011771號