Dubbo Service Registration and Publishing Mechanism

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

Tags: Dubbo Spring ServiceRegistration AnnotationProcessing BeanDefinitionRegistryPostProcessor

Posted on Thu, 22 Oct 2026 16:46:38 +0000 by simulant