Dubbo服务发布注册

服务发布注册的入口(@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
  • 服务注册

附上这个流程的流程图:

参考:

org.apache.dubbo 2.7.7 服务发布注册源码

原文地址:https://www.cnblogs.com/snail-gao/p/14195324.html