likes
comments
collection
share

Dubbo源码|九、Dubbo与Spring整合原理—@DubboService

作者站长头像
站长
· 阅读数 12

Dubbo与Spring整合系列

一、Dubbo与Spring整合原理——配置解析

二、Dubbo与Spring整合原理——@DubboService解析

三、Dubbo与Spring整合原理——@DubboReference解析

源码分析

本文主要介绍Dubbo@DubboService注解的解析过程。

配置扫描路径

DubboComponentScan可以指定扫描路径,也可以指定扫描类。

例如:

// 指定扫描路径方式
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
// 指定扫描类对应的包名方式
@EnableDubbo(scanBasePackageClasses = ProviderConfiguration.class)

Spring在解析DubboComponentScan注解时,会导入DubboComponentScanRegistrar这个类,这个类是解析Dubbo注解、路径的入口类。

@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
    String[] value() default {};
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
}

解析扫描路径以及Dubbo注解

DubboComponentScanRegistrar类实现了ImportBeanDefinitionRegistrar接口,在spring启动时,会调用registerBeanDefinitions方法。

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
    registerServiceClassPostProcessor(packagesToScan, registry);
    registerCommonBeans(registry);
}

这个方法主要处理过程如下:

  1. 获取扫描路径
  2. 扫描解析并处理@DubboService注解
  3. 处理@DubboReference注解

获取扫描路径

Dubbo源码|九、Dubbo与Spring整合原理—@DubboService

该方法解析DubboComponentScan注解,获取注解属性值,即basePackagesbasePackageClassesvalue的值。其中,basePackagesvalue都是路径,而basePackageClasses是一个类的集合,Dubbo会截取类的package路径,最终返回的是解析路径的集合。

注册BeanPostProcessor

该方法主要作用为:

  1. ServiceClassPostProcessor注册为一个Bean
  2. 由于ServiceClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,所以在Spring启动时会调用postProcessBeanDefinitionRegistry方法
  3. 扫描哪些类上加了@DubboService注解了,把这些类解析并生成BeanDefinition,生成两个类,一个为普通的Bean,一个为ServiceBean
  4. 在生成的ServiceBean中会监听ServiceBeanExportedEvent事件,在Spring容器启动完后,对Dubbo服务进行导出
private void registerServiceClassPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    BeanDefinitionBuilder builder = rootBeanDefinition(ServiceClassPostProcessor.class);
    builder.addConstructorArgValue(packagesToScan);
    builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}

此方法,将ServiceClassPostProcessor类生成为RootBeanDefinition,把扫描的路径作为ServiceClassPostProcessor类的构造方法参数,设置Bean的角色为ROLE_INFRASTRUCTURE与AOP有关,然后将生成的BeanDefinition进行注册。

ServiceClassPostProcessor实现类BeanDefinitionRegistryPostProcessor接口,在spring启动的时候,会调用postProcessBeanDefinitionRegistry方法。

处理BeanDefinition

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
    Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
    if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
        registerServiceBeans(resolvedPackagesToScan, registry);
    } else {
        if (logger.isWarnEnabled()) {
            logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
        }
    }
}

此方法,现将DubboBootstrapApplicationListener注册成一个Bean,主要是用来监听spring的刷新和关闭事件。

调用resolvePackagesToScan方法对传进来的路径进行解析,替换占位符。

调用registerServiceBeans方法将对扫描到的类注册为ServiceBean

注册ServiceBean

Dubbo源码|九、Dubbo与Spring整合原理—@DubboService

先定义一个扫描器,对传进来的扫描路径扫描哪些类上含有DubboServiceorg.apache.dubbo.config.annotation.Servicecom.alibaba.dubbo.config.annotation.Service3个注解,如果类上有这些注解,就把这些类生成对应的BeanDefinition,然后再把BeanDefinition注册为Spring容器里的Bean。

拿到了BeanDefinition,接下来就该把BeanDefinition生成对应ServiceBean。通过调用registerServiceBean方法注册ServiceBean

Dubbo源码|九、Dubbo与Spring整合原理—@DubboService

该方法主要处理过程如下:

  1. 调用resolveClass方法,将BeanDefinition中的beanClassName进行加载,生成类对象。
  2. 解析@DubboService注解,获取注解里配置的属性值。
  3. 解析实现类对应的接口。
  4. 获取BeanDefinition中的beanName,为ServiceBeanref属性值做准备。
  5. 调用buildServiceBeanDefinition构造出ServiceBeanDefinition
  6. 将构造出的ServiceBeanDefinition进行注册。

构建DubboService的BeanDefinition

Dubbo源码|九、Dubbo与Spring整合原理—@DubboService Dubbo源码|九、Dubbo与Spring整合原理—@DubboService

该方法主要处理过程如下:

  1. ServiceBean生成一个RootBeanDefinition
  2. 拿到这个BeanDefinition所有属性
  3. 通过propertyValues.addPropertyValues,将@DubboService注解配置的信息赋值给ServiceBean对应的BeanDefinition。被忽略的属性ignoreAttributeNames除外,因为这些属性有些特殊,不是简单数据类型,需要进行特殊处理。propertyValues可以对一些简单的数据类型进行赋值,比如String、int等。
  4. 调用addPropertyReference方法为ref属性进行赋值,传进去的参数数beanName,spring 根据beanName去找到对应的bean对象,赋值是beanName对应的具体对象。
  5. 为其他刚才忽略的属性进行赋值,providerapplicationmodule等。
  6. registryprotocol可以为多个值的属性,进行转换为RuntimeBeanReference集合进行赋值。

后记

@DubboService解析以及处理基本上已经结束了,至于Dubbo是如何对外暴露提供服务的,这块后面再进行介绍。