Dubbo学习之DubboService

相关阅读

简介

本文基于Spring Boot 2.6.6dubbo-spring-boot-starter 3.0.6环境。

本文主要分析Dubbo中注解DubboService的使用方式,并从源码分析其生效的实现原理;

使用

常用的使用方式有两种,下面分别介绍;

方式一

在实现类上使用@DubboService,表示该Bean为Dubbo Service,示例代码如下:

@DubboService
public class DemoServiceImpl implements DemoService {
}

方式二

官方推荐在BeanMethod上使用@DubboService

示例代码如下:

@Configuration
public class ReferenceConfig {

    @Bean
    @DubboService
    public DemoService demoServiceImpl() {
       return new DemoServiceImpl();
    }
}

解析

注解DubboService的解析由ServiceAnnotationPostProcessor完成,它会将标注了@DubboService的类或者Bean以ServiceBean形式注册到Spring容器中,以便后续创建Dubbo Service

  1. postProcessBeanDefinitionRegistry方法用于解析方式一的@DubboService
  2. postProcessBeanFactory方法用于解析方式二的@DubboService

方式一

ServiceAnnotationPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,在其postProcessBeanDefinitionRegistry方法中,会根据设置的resolvedPackagesToScan(待扫描路径),处理对应路径下标注了@DubboService(本文仅关注DubboService,实际还包括:org.apache.dubbo.config.annotation.Servicecom.alibaba.dubbo.config.annotation.Service)的类,代码如下:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    this.registry = registry;
    // 扫描resolvedPackagesToScan路径下标注了@DubboService的类
    // packagesToScan由参数dubbo.scan.base-packages配置
    // 若该参数不存在,那么ServiceAnnotationPostProcessor也不会存在于Spring容器
    scanServiceBeans(resolvedPackagesToScan, registry);
}

private void scanServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

    // 设置扫描标识,避免重复扫描
    scaned = true;
    if (CollectionUtils.isEmpty(packagesToScan)) {
        // 无路径需要扫描,则直接退出
        if (logger.isWarnEnabled()) {
            logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
        }
        return;
    }

    // 配置DubboClassPathBeanDefinitionScanner
    DubboClassPathBeanDefinitionScanner scanner =
            new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);

    BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
    scanner.setBeanNameGenerator(beanNameGenerator);
    for (Class<? extends Annotation> annotationType : serviceAnnotationTypes) {
        // 基于注解的类型过滤器
        scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
    }

    ScanExcludeFilter scanExcludeFilter = new ScanExcludeFilter();
    scanner.addExcludeFilter(scanExcludeFilter);

    // 扫描各个包路径
    for (String packageToScan : packagesToScan) {
        // 如果已经扫描过则跳过
        if (servicePackagesHolder.isPackageScanned(packageToScan)) {
            if (logger.isInfoEnabled()) {
                logger.info("Ignore package who has already bean scanned: " + packageToScan);
            }
            continue;
        }

        // 扫描包路径下被Dubbo Service注解标注的类,并生成BeanDefinition
        scanner.scan(packageToScan);

        // 查找Dubbo Service的BeanDefinitionHolder
        // 结果会在scan中缓存,故此次直接从缓存中得到
        Set<BeanDefinitionHolder> beanDefinitionHolders =
                findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);

        if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
            if (logger.isInfoEnabled()) {
                List<String> serviceClasses = new ArrayList<>(beanDefinitionHolders.size());
                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                    serviceClasses.add(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
                }
                logger.info("Found " + beanDefinitionHolders.size() + " classes annotated by Dubbo @Service under package [" + packageToScan + "]: " + serviceClasses);
            }

            for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                // 向容器中注册该beanDefinitionHolder
                processScannedBeanDefinition(beanDefinitionHolder, registry, scanner);
                // 缓存已扫描过的类
                servicePackagesHolder.addScannedClass(beanDefinitionHolder.getBeanDefinition().getBeanClassName());
            }
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn("No class annotated by Dubbo @Service was found under package ["
                        + packageToScan + "], ignore re-scanned classes: " + scanExcludeFilter.getExcludedCount());
            }
        }

        // 缓存已扫描过的包路径
        servicePackagesHolder.addScannedPackage(packageToScan);
    }
}

主要逻辑为:

  1. 扫描标注@DubboService的Class,并注册到Spring容器;
  2. 将注册的BeanDefinition,再以ServiceBean注册到Spring容器

扫描标注@DubboService的Class

ClassPathBeanDefinitionScanner.scan(packageToScan)内部使用doScan实现,其代码如下:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {
        // 查找满足要求的候选组件Dubbo Service Class
        // 对basePackage路径下所有类经过isCandidateComponent筛选
        //     先经过excludeFilters(优先),再经过includeFilters
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        for (BeanDefinition candidate : candidates) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            // 校验当前容器是否已存在该BeanDefinition
            // 1. 若不存在则校验通过
            // 2. 若存在,但兼容,则校验不通过
            // 3. 若存在,且不兼容,则抛出异常
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                // 注册BeanDefinition,此时beanName根据原始类名生成
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}

注册ServiceBean

processScannedBeanDefinition代码如下:

private void processScannedBeanDefinition(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
                                          DubboClassPathBeanDefinitionScanner scanner) {

    Class<?> beanClass = resolveClass(beanDefinitionHolder);

    // 获取类上标注的Dubbo Service注解
    Annotation service = findServiceAnnotation(beanClass);

    // 获取注解的属性
    Map<String, Object> serviceAnnotationAttributes = AnnotationUtils.getAttributes(service, true);

    String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);

    String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();

    // 构造ServiceBean BeanName
    // ServiceBean:interfaceName
    String beanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);

    // 构造ServiceBean BeanDefinition
    AbstractBeanDefinition serviceBeanDefinition =
            buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, annotatedServiceBeanName);

    // 注册ServiceBean BeanDefinition
    // 此时beanName为ServiceBean:interfaceName
    registerServiceBeanDefinition(beanName, serviceBeanDefinition, serviceInterface);
}

方式二

ServiceAnnotationPostProcessor.postProcessBeanFactory方法中,会处理标注了@DubboService(本文仅关注DubboService,实际还包括:org.apache.dubbo.config.annotation.Servicecom.alibaba.dubbo.config.annotation.Service)的BeanMethod,代码如下:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    if (this.registry == null) {
        // 未在postProcessBeanDefinitionRegistry中设置,则此时设置
        this.registry = (BeanDefinitionRegistry) beanFactory;
    }

    // 处理由标注了Dubbo Service注解的BeanMethod得到的BeanDefinition
    String[] beanNames = beanFactory.getBeanDefinitionNames();
    for (String beanName : beanNames) {
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
        Map<String, Object> annotationAttributes = getServiceAnnotationAttributes(beanDefinition);
        // 存在则说明BeanMethod上存在Dubbo Service注解
        if (annotationAttributes != null) {
            // 注册为Dubbo Service BeanDefinition
            processAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition, annotationAttributes);
        }
    }

    if (!scaned) {
        // 还未扫描过,则扫描
        scanServiceBeans(resolvedPackagesToScan, registry);
    }
}

private void processAnnotatedBeanDefinition(String refServiceBeanName, AnnotatedBeanDefinition refServiceBeanDefinition, Map<String, Object> attributes) {

    Map<String, Object> serviceAnnotationAttributes = new LinkedHashMap<>(attributes);

    // get bean class from return type
    String returnTypeName = SpringCompatUtils.getFactoryMethodReturnType(refServiceBeanDefinition);
    Class<?> beanClass = resolveClassName(returnTypeName, classLoader);

    String serviceInterface = resolveInterfaceName(serviceAnnotationAttributes, beanClass);

    // 构造ServiceBean BeanName
    // ServiceBean:interfaceName
    String serviceBeanName = generateServiceBeanName(serviceAnnotationAttributes, serviceInterface);

    AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(serviceAnnotationAttributes, serviceInterface, refServiceBeanName);

    // set id
    serviceBeanDefinition.getPropertyValues().add(Constants.ID, serviceBeanName);

    // 注册ServiceBean BeanDefinition
    // 此时beanName为ServiceBean:interfaceName
    registerServiceBeanDefinition(serviceBeanName, serviceBeanDefinition, serviceInterface);
}

至此,@DubboService的源码分析就结束啦,ServiceBean的实例化请见下文分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值