The entry point for Dubbo service registration begins with the @DubboComponentScan annotatoin:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
This annotation leverages Spring’s @Import mechanism to register DubboComponentScanRegistrar, which implements ImportBeanDefinitionRegistrar. This interface allows custom bean definitions to be registered during application context startup. The core logic resides in the registerBeanDefinitions method:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Set<String> packages = getPackagesToScan(metadata);
registerServiceAnnotationBeanPostProcessor(packages, registry);
registerCommonBeans(registry);
}
The key step is the registration of ServiceAnnotationBeanPostProcessor:
private void registerServiceAnnotationBeanPostProcessor(Set<String> packages, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
builder.addConstructorArgValue(packages);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
}
Although marked as deprecated in newer versions, ServiceAnnotationBeanPostProcessor plays a critical role by implementing BeanDefinitionRegistryPostProcessor. Its postProcessBeanDefinitionRegistry method triggers service scanning:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
registerBeans(registry, DubboBootstrapApplicationListener.class);
Set<String> resolvedPackages = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackages)) {
registerServiceBeans(resolvedPackages, registry);
}
}
The registerServiceBeans method uses a customized scanner to detect classes annotated with Dubbo service annotations:
private void registerServiceBeans(Set<String> packages, BeanDefinitionRegistry registry) {
DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
scanner.setBeanNameGenerator(resolveBeanNameGenerator(registry));
// Support multiple service annotations for backward compatibility
serviceAnnotationTypes.forEach(type -> scanner.addIncludeFilter(new AnnotationTypeFilter(type)));
for (String pkg : packages) {
scanner.scan(pkg);
Set<BeanDefinitionHolder> holders = findServiceBeanDefinitionHolders(scanner, pkg, registry, scanner.getBeanNameGenerator());
if (!CollectionUtils.isEmpty(holders)) {
for (BeanDefinitionHolder holder : holders) {
registerServiceBean(holder, registry, scanner);
}
}
}
}
The supported annotations include:
private static final List<Class<? extends Annotation>> serviceAnnotationTypes = Arrays.asList(
DubboService.class, // New standard since 2.7.7
org.apache.dubbo.config.annotation.Service.class, // Apache Dubbo legacy
com.alibaba.dubbo.config.annotation.Service.class // Alibaba Dubbo legacy
);
Each detected service class is processed in registerServiceBean, which constructs a ServiceBean definition containing configuration such as protocol, load balancing, and port:
private void registerServiceBean(BeanDefinitionHolder holder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) {
Class<?> beanClass = resolveClass(holder);
Annotation service = findServiceAnnotation(beanClass);
AnnotationAttributes attrs = getAnnotationAttributes(service, false, false);
Class<?> interfaceClass = resolveServiceInterfaceClass(attrs, beanClass);
String beanName = holder.getBeanName();
AbstractBeanDefinition serviceBeanDef = buildServiceBeanDefinition(service, attrs, interfaceClass, beanName);
String serviceBeanName = generateServiceBeanName(attrs, interfaceClass);
if (scanner.checkCandidate(serviceBeanName, serviceBeanDef)) {
registry.registerBeanDefinition(serviceBeanName, serviceBeanDef);
}
}
This registers a ServiceBean instance into the Spring container. While its constructor is minimal, initialization completes via afterPropertiesSet(), which sets the service path if not explicitly defined.
Crucially, the earlier-registered DubboBootstrapApplicationListener listens for ContextRefreshedEvent:
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
dubboBootstrap.start();
}
}
This triggers Dubbo’s bootstrap process, wich:
- Initializes metadata and remote configurasions
- Constructs service URLs
- Starts embedded servers (e.g., Netty for dubbo://)
- Registers services with the configured registry