Dubbo源码解读-dubbo启动与Spring整合之@ DubboComponentScan

       上篇我们介绍了Dubbbo整合Spring中的@EnableDubboConfig注解源码分析,地址如下

Dubbo源码解读-dubbo启动与Spring整合-CSDN博客

        本文主要针对@ DubboComponentScan注解,从dubbo源码角度解析该注解功能。

        接着说明,读Dubbo源码最好是先对Spring源码有一定的了解。如果大家需要,我也可以针对Spring框架做一系列源码的解读专栏。

         不过不用担心,如果需要Spring的源码知识,文章中也会进行Spring源码铺垫介绍的。

        如果内容中有没描述清楚的,或者大家在阅读源代码有疑问的,欢迎留言,看到就会及时回复。

        为了更清楚的分析解释源码,源代码中部分不重要的内容可能会删减,保留重要内容方便大家理解。

主要内容

  1. @ DubboComponentScan解析
  2. ServiceAnnotationBeanPostProcessor源码解析
  3. ReferenceAnnotationBeanPostProcessor源码解析

@DubboComponentScan解析

        该标签的主要职责其实就是负责注册两个BeanPostProcessor,分别是ServiceAnnotationBeanPostProcessor和ReferenceAnnotationBeanPostProcessor,分别负责处理@Service和@Reference注解。

 具体流程如下:

  1. 注解上import了DubboComponentScanRegistrar类。

  2. DubboComponentScanRegistrar实现了ImportBeanDefinitionRegistrar接口,会在Spring启动过程中,调用registerBeanDefinitions方法()

  3. 注册ServiceAnnotationBeanPostProcessor类BeanDefinition

  4. 注册ReferenceAnnotationBeanPostProcessor类BeanDefinition

Spring背景知识铺垫

Spring容器管理的类,不论是通过xml加载的还是注解加载的,都需要先进行收集成Beandefinetion对象,然后再根据该对象进程Bean 的实例化。实例化完成之后交给Spring管理。

  1. @Import注解对应的类会在,Spring启动过程中由 ConfigurationClassPostProcessor扫描,收集@Import注解
  2. 实现ImportBeanDefinitionRegistrar的类,在Spring启动过程中ConfigurationClassPostProcessor调用对应类中的registerBeanDefinitions()方法如DubboComponentScanRegistrar中的

源码流程

  • 流程1
#Import标签倒入注册类
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
}
  • 流程2 /3/4
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);

        //注册ServiceAnnotationBeanPostProcessor
        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);

        注册ReferenceAnnotationBeanPostProcessor
        registerReferenceAnnotationBeanPostProcessor(registry);

    }
}

ServiceAnnotationBeanPostProcessor

负责对@Service注解支持。

具体流程:

  1. 创建DubboClassPathBeanDefinitionScanner继承自ClassPathBeanDefinitionScanner
  2. doScan对包下面的类进行扫描,获取所有包含@service注解的类,并封装成BeanDefinition,注册到Registry中
  3. 创建ServiceBean类的BeanDefinition(每个@service注解的类都对应一个ServiceBean)
  4. 根据@service注解,填充ServiceBean的BeanDefinition的属性。
    1. .class属性.interface,ref等
  5. 注册
  6. 特殊说明:一个@Service注解修饰的类,会对应两个beanDefinition.上面2/3。

Spring背景知识铺垫

  1. Spring通过BeanPostProcessor实现在启动过程中的埋点功能,比如手机@autowire注解,@resource,完成IOC,创建AOP代理等。
  2. 实现BeanDefinitionRegistryPostProcessor的类会在Spring创建完BeaFacotry之后,执行invokeBeanFactoryPostProcessors会调用BeanDefinitionRegistryPostProcessor实现类对应的registryPostProcessor()方法
  3. 上面2中具体流程Application.refresh()->invokeBeanFactoryPostProcessors()->BeanDefinitionRegistryPostProcessor.registryPostProcessor()

源码流程

  • ServiceAnnotationBeanPostProcessor.postProcessBeanDefinitionRegistry
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        //解析扫描包 com.*.* 
        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!");
            }
        }

    }
  • ServiceAnnotationBeanPostProcessor.registreServiceBeans流程2/3/4
private void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

        DubboClassPathBeanDefinitionScanner scanner =
                new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);

        //设置要扫描的注解 。这里就是@Servcie注解
        scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));

        for (String packageToScan : packagesToScan) {

            //  这个方法比较庞大。具体流程就是:
            //1.先扫描路径下所有的class文件
            //2.查看class上面是否有对应的@service注解
            //3.创建BeanDefinition对象
            //4.绑定属性值
            //5.注册BeanDefinition.
            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)) {

                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                    //这里会针对每个被@Service修饰的类,创建一个ServiceBean类型的BeanDefinition.
                    registerServiceBean(beanDefinitionHolder, registry, scanner);
                }

            }

        }

    }

ReferenceAnnotationBeanPostProcessor

负责对@Reference的支持

具体流程

  1. 收集@reference注解元数据
  2.  完成依赖注入

Spring背景知识铺垫

BeanPostProcessor知识点:

  • 实现MergedBeanDefinitionPostProcessor接口会在Spring启动过程中,bean创建实例之后调用postProcessMergedBeanDefinition方法。
  • 实现InstantiationAwareBeanPostProcessor类会在Spring启动过程中,通过populateBean()调用postProcessProperties()方法完成IOC依赖注入。

注解依赖注入实现流程

  1. 自定义BeanPostProcessor
  2. 收集注解:实现MergedBeanDefinitionPostProcessor重写postProcessMergedBeanDefinition方法。
  3.  依赖注入:继承InstantiationAwareBeanPostProcessor重写postProcessProperties方法

 源码流程

  • 收集@Reference。类调用关系:ReferenceAnnotationBeanPostProcessor->AnnotationInjectedBeanPostProcessor.postProcessMergedBeanDefinition()->findInjectionMetadata()->buildAnnotatedMetadata()
private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
        //收集类中被@Reference的字段
        Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
        //收集类中被@Reference修饰的方法
        Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
        //包装成InjectMetadata对象,持有上面两个集合,方便后面依赖注入
        return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);

    }
  • 完成依赖注入:拿到上一步收集结果,对有@Reference注解的属性和方法进行依赖注入.类调用关系:ReferenceAnnotationBeanPostProcessor->AnnotationInjectedBeanPostProcessor.postProcessPropertyValues()
//AnnotationInjectedBeanPostProcessor.class
public PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

        //收集有@Reference注解的属性和方法  copy的spring代码
        InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        } catch (BeanCreationException ex) {
            throw ex;
        } catch (Throwable ex) {
           
        }
        return pvs;
    }
//AnnotationInjectedBeanPostProcessor.class
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {

            Class<?> injectedType = field.getType();
            //获取需要依赖注入的实例
            injectedBean = getInjectedObject(annotation, bean, beanName, injectedType, this);

            ReflectionUtils.makeAccessible(field);

            field.set(bean, injectedBean);

        }
//ReferenceAnnotationBeanPostProcessor.class
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType,
                                       InjectionMetadata.InjectedElement injectedElement) throws Exception {

        //创建referencedbean的名称
        String referencedBeanName = buildReferencedBeanName(reference, injectedType);

        //创建ReferenceBean
        ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
        //field和method的injectedElement,和ReferenceBean建立缓存
        cacheInjectedReferenceBean(referenceBean, injectedElement);
        //创建需要依赖注入的代理实例
        Object proxy = buildProxy(referencedBeanName, referenceBean, injectedType);

        return proxy;
    }

总结:上面内容中,每个注解都从业务流程和源码角度进行了详细分析,依赖的Spring源码知识点也做了说明,如果大家有疑问或者对文章排版任何方面有建议都可以留言评论,看到都会及时回复大家。

知识总结,分享不易,全文手敲,欢迎大家点赞评论收藏。

下一篇:Dubbo源码解读-dubbo的SPI机制-CSDN博客

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: dubbo-spring-boot-starter是一个基于Spring Boot框架的Dubbo服务框架的启动器。它可以帮助开发者快速集成Dubbo服务框架到Spring Boot应用中,简化了Dubbo服务的配置和使用。通过使用dubbo-spring-boot-starter,开发者可以更加方便地实现Dubbo服务的注册、发现、调用等功能,提高了开发效率和代码质量。 ### 回答2: Dubbo-Spring-Boot-Starter是一款用于在Spring Boot应用中接入Apache Dubbo的开源框架。它可以帮助开发人员快速、方便地实现DubboSpring Boot项目中的集成和使用。 Dubbo是基于Java的高性能、轻量级分布式服务框架,帮助开发者更轻松、更透明地构建分布式服务,同时它也是阿里巴巴开源的一款优秀的分布式框架。然而,Dubbo在使用过程中存在一些繁琐的配置,为开发人员增加了很多工作量和麻烦,而Dubbo-Spring-Boot-Starter则是为了消除这些繁琐的配置和使用难度而产生的。 在使用Dubbo-Spring-Boot-Starter之后,开发人员可以将DubboSpring Boot框架快速整合,并通过简单的配置实现Dubbo的相关功能,比如注册中心、服务提供者和服务消费者等。在使用过程中,Dubbo-Spring-Boot-Starter为开发人员提供了大量的自动化配置和默认值,比如默认的Dubbo协议、负载均衡策略、超时时间等,同时支持自定义扩展自动配置的方式。此外,Dubbo-Spring-Boot-Starter还提供了一些Web端的监控和管理功能,帮助开发人员更方便地进行运维和监控。 总之,Dubbo-Spring-Boot-Starter是对DubboSpring Boot框架的完美结合,它简化了DubboSpring Boot项目中的使用和配置,提高了开发效率,降低了使用成本,是一款值得开发人员尝试的框架。 ### 回答3: Dubbo-spring-boot-starter是Spring Boot与Dubbo框架集成的一个starter,它提供了快速集成Dubbo框架的能力。Dubbo是一款分布式的服务治理框架,支持高性能的异步通信,并提供了负载均衡、服务降级、集群容错等丰富的特性。 Dubbo-spring-boot-starter包含了Dubbo所需的基本配置信息,只需要在Spring Boot项目的配置文件中添加相应的配置即可快速集成Dubbo框架。通过简单的配置,Dubbo-spring-boot-starter能够让Spring Boot项目成为Dubbo服务的提供者或消费者。 Dubbo-spring-boot-starter的使用非常方便,只需要在项目中添加对应的依赖即可开始使用,它提供了多种配置方式,如注解、XML和properties等。同时,Dubbo-spring-boot-starter也提供了丰富的自定义配置选项,可以满足不同场景的需求。 除了Dubbo-spring-boot-starter,还有其他与Dubbo框架集成的starter,如dubbo-spring-cloud-starter和dubbo-spring-boot-project。这些starter都提供了方便快捷的Dubbo集成方式,使得Dubbo框架在Spring Boot生态中的应用更加广泛。 总之,Dubbo-spring-boot-starter是一款优秀的starter,可以让Spring Boot项目快速集成Dubbo框架,提供或消费Dubbo服务,为分布式服务治理带来便利。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值