Dubbo源码一:【Dubbo与Spring整合】

正常在项目中,我们都是在Spring环境下使用Dubbo,所以我们这里就在Spring的环境下看看Dubbo是如何运作的

入口

在源码下载下来之后,有一个dubbo-demo目录,里面有一个基于spring注解的子目录dubbo-demo-annotation, 里面有一个生产者的demo,还有一个消费者的demo
image.png
Provider下面的Application:

public class Application {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
        context.start();
        System.in.read();
    }

    /**
     * 1、EnableDubbo
     * 2、DubboBootstrapApplicationListener监听容器启动事件,然后调用DubboBootstrap的start方法
     *          1、会导出DubboService
     *          2、会订阅DubboService
     * 3、
     */
    @Configuration
    @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
    @PropertySource("classpath:/spring/dubbo-provider.properties")
    static class ProviderConfiguration {
        @Bean
        public RegistryConfig registryConfig() {
            RegistryConfig registryConfig = new RegistryConfig();
            registryConfig.setAddress("zookeeper://127.0.0.1:2181");
            return registryConfig;
        }
    }
}

dubbo-provider.properties
image.png

Consumer下面的Application:

public class Application {
    /**
     * In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before
     * launch the application
     */
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConsumerConfiguration.class);
        context.start();
        DemoService service = context.getBean("demoServiceComponent", DemoServiceComponent.class);
        String hello = service.sayHello("world");
        System.out.println("result :" + hello);
    }

    @Configuration
    @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.consumer.comp")
    @PropertySource("classpath:/spring/dubbo-consumer.properties")
    @ComponentScan(value = {"org.apache.dubbo.demo.consumer.comp"})
    static class ConsumerConfiguration {

    }
}

dubbo-consumer.properties
image.png

Provider#Application

@PropertySource(“classpath:/spring/dubbo-provider.properties”)

这个注解是Spring注解,负责解析配置文件,把解析到的文件放到Environment对象中。而Dubbo就是从这个对象里面拿到配置值,生成对应的对象,比如 dubbo.application.name会生成一个ApplicationConfig,比如dubbo.protocal.* 会生成一个ProtocalConfig对象

@EnableDubbo(scanBasePackages = “org.apache.dubbo.demo.provider”)

image.png

@EnableDubboConfig

完成对Dubbo配置的解析,把配置文件里面的内容解析成一个一个配置对象
image.png

import一个DubboConfigConfigurationRegistrar
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        /** 此方法主要作用:
         * 会对Properties文件进行解析,主要完成的事情是根据Properties文件的每个配置项的前缀、参数名、参数值生成对应的Bean。
         *  比如前缀为"dubbo.application"的配置项,会生成一个 ApplicationConfig  类型的BeanDefinition。
         *  比如前缀为"dubbo.protocol"的配置项,会生成一个  ProtocolConfig  类型的BeanDefinition。
         *
         *  都有哪些配置类? 具体看:
         *    1、DubboConfigConfiguration.Single
         *    2、DubboConfigConfiguration.Multiple
         */
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));

        boolean multiple = attributes.getBoolean("multiple");

        // Single Config Bindings
        // todo 在解析DubboConfigConfiguration.Single会注入ConfigurationBeanBindingsRegister
        registerBeans(registry, DubboConfigConfiguration.Single.class);

        if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
            /**
             * 默认情况下开启了multiple模式,multiple模式表示开启多配置模式,意思是这样的:
               1、如果没有开启multiple模式,那么只支持配置一个dubbo.protocol,比如:
                         dubbo.protocol.name=dubbo
                         dubbo.protocol.port=20880
                         dubbo.protocol.host=0.0.0.0
               2、如果开启了multiple模式,那么可以支持多个dubbo.protocol,比如:
                        dubbo.protocols.p1.name=dubbo
                        dubbo.protocols.p1.port=20880
                        dubbo.protocols.p1.host=0.0.0.0

                        dubbo.protocols.p2.name=http
                        dubbo.protocols.p2.port=8082
                        dubbo.protocols.p2.host=0.0.0.0
             */
            registerBeans(registry, DubboConfigConfiguration.Multiple.class);
        }

        // Since 2.7.6 todo 看这里
        registerCommonBeans(registry);
  }

总结一下做了几件事:

  1. 先往Spring容器注册了一个DubboConfigConfiguration.Single.class, 导致上面有注解引入了@EnableConfigurationBeanBindings

image.png
image.png

在EnableConfigurationBeanBindings上面import了ConfigurationBeanBindingsRegister, 又是相似的套路
image.png
ConfigurationBeanBindingsRegister也实现了ImportBeanDefinitionRegistrar接口,所以也会在Spring启动的时候调用到,我们能看到它做了做了几步

  1. 从EnableConfigurationBeanBindings 中获取注解的值,然后在获取value的属性值,value对应的是EnableConfigurationBeanBinding 中的值

image.png

  1. 创建一个ConfigurationBeanBindingRegistrar�类,将environment设置到里面,然后调用registerConfigurationBeanDefinitions方法

image.png
image.png
image.png
registerConfigurationBeanDefinition这里做了这样几件事:
1、从注解中获取prefix(如果里面有占位符,需要从environment中获取)、type(返回是一个class值,比如ApplicationConfig)、multiple
2、registerConfigurationBeans -> PropertySourcesUtils.getSubProperties从配置文件中取出对应的配置
3、registerConfigurationBeans -> registerConfigurationBean:将对应的Config(比如ApplicationConfig)注册到spring容器中
4、!!!registerConfigurationBindingBeanPostProcessor(registry):注册了一个ConfigurationBeanBindingPostProcessor�, 为什么需要这个类,因为目前我们只是把配置类做成BD放到Spring容器中,但是我们并没有赋值,所以需要在这个后置处理器中给这些BD赋值

  1. 如果开启了multiple, 会往spring中注册一个DubboConfigConfiguration.Multiple.class
  2. 调用registerCommonBeans, 往Spring容器中配置很多Dubbo需要的Bean,比如ReferenceAnnotationBeanPostProcessor�(处理@dubbo_reference注解的)、DubboApplicationListenerRegistrar�(用来创建很多的Listener,在spring启动过程中,dubbo需要做的一些事)等

image.png

总结一下DubboConfigConfigurationRegistrar做的事
  1. 往Spring容器中放一个DubboConfigConfiguration.Single�类,

image.png
Single就是一个配置模版类,上面会有@EnableConfigurationBeanBindings,这个类又会注入一个类ConfigurationBeanBindingsRegister�,这个类实现了ImportBeanDefinitionRegistrar�, 会在Spring启动的时候调用到它的registerBeanDefinitions,这个方法最终完成了将Single上面这些个配置
image.png
转换成XXXConfig, 同时还注册了一个ConfigurationBeanBindingPostProcessor,完成从配置文件读取这一个个配置,并放到XXXConfig中

  1. 如果配置的multiple=true,就会多走一套multiple配置逻辑,核心逻辑和Single其实差不错
  2. registerCommonBeans:注册了很多Dubbo中用到的通用bean


@DubboComponentScan

image.png
�这里同样引入了一个DubboComponentScanRegistrar,也就是在spring启动的过程中会调用到它的registerBeanDefinitions方法
image.png
getPackagesToScan: 返回一个需要扫描的路径集合

image.png

registerServiceAnnotationBeanPostProcessor(packagesToScan, registry): 又往spring容器中注册了一个ServiceAnnotationBeanPostProcessor类,通过传入了刚刚获取的需要扫描的路径集合
image.png

ServiceAnnotationBeanPostProcessor

image.png
ServiceAnnotationBeanPostProcessor继承的是ServcieClassPostProcessor
image.png
image.png
这里做了几件事:

  1. 注册DubboBootstrapApplicationListener到spring容器中,这个listener负责监听ContextRefreshedEvent事件
  2. 如果packagesToScan中有占位符,替换掉,然后使用registerServiceBeans, 将@DubboServcie扫描到Spring容器中

ServiceClassPostProcessor.registerServiceBeans(packagesToScan, BeanDefinitionRegistry registry)

image.png
总结一下:

  1. 创建了一个DubboClassPathBeanDefinitionScanner专门用来扫指定路径包下面的beanDefinition的
  2. 给scanner设置了IncludeFilter,就是我只扫@DubboService、@Service这些注解的
  3. 遍历路径包,然后使用scanner.scan来看路径包下面有@DubboService、@Service的beanDefinition
  4. 将扫到的BeanDefinition,然后调用registerServiceBean 将这些spring的bean处理成Dubbo自己的bean

ServiceClassPostProcessor.registerServiceBean()

image.png

Consumer#Application

image.png

Consumer的大体逻辑和Provider一样,肯定也有读取配置的地方,最重要的地方就是@DubboReference是如何解析的

入口

@EnableDubboConfig -> @Import(DubboConfigConfigurationRegistrar.class) ->DubboConfigConfigurationRegistrar�.registerBeanDefinitions ->registerCommonBeans(registry);
image.png

ReferenceAnnotationBeanPostProcessor

image.png
这个类其实挺有意思的,它继承了AbstractAnnotationBeanPostProcessor,
image.png
这个AbstractAnnotationBeanPostProcessor又继承了InstantiationAwareBeanPostProcessorAdapter�,我们来看一下它的实现类有哪些?
image.png
是不是非常的熟悉,AutoWiredAnnotationBeanPostProcessor,其实@ReferencService和@AutoWired的实现原理是一样的,都是在Spring依赖注入的时候,需要做属性的注入,最终会调用到ReferenceAnnotationBeanPostProcessor.doGetInjectedBean

ReferenceAnnotationBeanPostProcessor.doGetInjectedBean

image.png
一共做了几件事:

  1. buildReferencedBeanName�

image.png
image.png
使用buildReferencedBeanName方法得到一个bean的名字,这个bean是需要引入服务的beanName,最终生成的格式为ServiceBean:org.apache.dubbo.demo.DemoService,如果说设置了group,或者version,都会拼接上去,最终生成的格式为:ServiceBean:interfaceClassName:version:group

  1. getReferenceBeanName�

image.png
image.png
getReferencBeanName得到的referenceBeanName是我引入时产生的服务名,而referencedBeanName对应的serviceBean的服务名称,从generateReferenceBeanName我们看的出来,referenceBeanName产生规则为:@Reference注解所有属性的值进行拼接,所以就是@Reference引入的接口是同一个,但注解的值不一样的话,这个名字也是不一样的。那么这个名字有什么用,他的作用是放到缓存中作为key

  1. buildReferenceBeanIfAbsent�

image.png
image.png
image.png

代码主要就是判断缓存中是否存在,如果不存在就进行创建流程,这里比较复杂,我们关系最终得到的referenceBean:
image.png

  1. isLocalServiceBean�

判断是否是本地服务

  1. registerReferenceBean�

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/382111.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯每日一题------背包问题(二)

前言 本次讲解背包问题的一些延申问题,新的知识点主要涉及到二进制优化,单调队列优化DP,树形DP等。 多重背包 原始做法 多重背包的题意处在01背包和完全背包之间,因为对于每一个物品它规定了可选的个数,那么可以考虑…

M1 Mac使用SquareLine-Studio进行LVGL开发

背景 使用Gui-Guider开发遇到一些问题,比如组件不全。使用LVGL官方的设计软件开发 延续上一篇使用的基本环境。 LVGL项目 新建项目 选择Arduino的项目,设定好分辨率及颜色。 设计UI 导出代码 Export -> Create Template Project 导出文件如图…

vue+springboot前后端视频文件等的上传与展示(基于七牛云)

前言:在初步说明完成功能之前,我会把重要的部分说明下。后续我会细化。 vue视频文件上传 其实这里和图片这些文件就是一样的。因为上传只是把我们想在云端展示的文件按等传输到云端的bucket。然后方便网站去请求引用。 有人问我我就说明下。这种东西无…

Linux 36.2@Jetson Orin Nano之Hello AI World!

Linux 36.2Jetson Orin Nano之Hello AI World! 1. 源由2. Hello AI World!3. 步骤3.1 准备阶段3.2 获取代码3.3 Python环境3.4 重点环节3.5 软件配置3.6 PyTorch安装3.7 编译链接3.8 安装更新 4. 测试4.1 video-viewer4.2 detectnet4.3 演示命令 5. 参考…

问题:2、计算机网络的目标是实现________。 #媒体#知识分享

问题:2、计算机网络的目标是实现________。 A.数据处理 B.信息传输与数据处理 C.资源共享与信息传输 D.文献查询 参考答案如图所示

开发者实战 | 如何在 Windows 上调用 NPU 部署深度学习模型

点击蓝字 关注我们,让开发变得更有趣 作者 | 杨亦诚 排版 | 李擎 OpenVINO™..♩~ ♫. ♪.. 相信很多小伙伴都已经知道,在最新一代的 Intel Core Ultra 移动端平台中已经集成了被称为 NPU 的神经网络加速处理器,以提供低功耗的AI算力,特别适合…

代码随想录算法训练营day15||二叉树part02、102.二叉树的层序遍历、 226.翻转二叉树(优先掌握递归)、101. 对称二叉树 (优先掌握递归)

102.二叉树的层序遍历 题目:给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。 接下来我们再来介绍二叉树的另一种遍历方式:层序遍历。 层序遍历一个二叉树。就是…

分布式搜索引擎 elasticsearch

分布式搜索引擎 elasticsearch 第一部分 1.初识elasticsearch 1.1.了解ES 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 例如: 在GitHub搜索…

酷开科技荣获消费者服务平台黑猫投诉“消费者服务之星”称号

什么是优质服务?既是以客户为中心的庄严承诺,又是对服务能力提升的深耕细作;既是对服务标准的敬畏,也是对服务创新的不断探索……服务是多维的,每个企业都有自己独到的诠释,或事无巨细环环严控,…

Mybatis开发辅助神器p6spy

Mybatis什么都好,就是不能打印完整的SQL语句,虽然可以根据数据来判断一二,但始终不能直观的看到实际语句。这对我们想用完整语句去数据库里执行,带来了不便。 怎么说呢不管用其他什么方式来实现完整语句,都始终不是Myb…

ongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(2)-Swagger框架集成

Swagger是什么? Swagger是一个规范且完整API文档管理框架,可以用于生成、描述和调用可视化的RESTful风格的 Web 服务。Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口,可以让人和计算机拥有无须访问源码、文档或网络流量监测就…

vivado不使用的引脚约束方法

不需要分配的引脚约束方法:收藏备用 方法一: 方法一: set_property SEVERITY {Warning} [get_drc_checks NSTD-1] set_property SEVERITY {Warning} [get_drc_checks RTSTAT-1] set_property SEVERITY {Warning} [get_drc_checks UCIO-1]#方法二 set_p…

Days 27 ElfBoard 板 AltiumDesigner 相同电路快速布局布线

在进行设计开发的时候,总会遇到相同的电路,或者模块,这些电路可以使用相同的布局和走线,例如 DC-DC 电源、网口 PHY 电路部分。这类型的电路,我们可以采用AltiumDesigner 中的 Room 进行布局和布线的快速复制&#xff…

参观宋代建筑,感受传统魅力

为了更好地了解和传承中华文化,同时深入挖掘其在现代社会的传承与发展,2024年2月8日,曲阜师范大学计算机学院“古韵新声,格物致‘知’”社会实践队队员饶子恒深入考察中国传统建筑和文化,前往山东省菏泽市郓城县的水浒…

数据库管理-第14期 Oracle Vector DB AI-01(20240210)

数据库管理149期 2024-02-10 数据库管理-第149期 Oracle Vector DB & AI-01(20240210)1 机器学习2 向量3 向量嵌入4 向量检索5 向量数据库5 专用向量数据库的问题总结 数据库管理-第149期 Oracle Vector DB & AI-01(20240210&#xf…

Python中HTTP隧道的基本原理与实现

HTTP隧道是一种允许客户端和服务器之间通过中间代理进行通信的技术。这种隧道技术允许代理服务器转发客户端和服务器之间的所有HTTP请求和响应,而不需要对请求或响应内容进行任何处理或解析。Python提供了强大的网络编程能力,可以使用标准库中的socket和…

波奇学Linux:文件重定向和虚拟文件系统

重定向 文件描述符所对应的分配规则,从0开始,寻找最小没有使用的数组位置。 如图所示,关闭文件描述符的0,新打开的文件描述符为0,而关闭2,文件描述符为2。 重定向:文件输出的对象发生改变 例…

【 buuctf snake 】

需要用到 Serpent 加密,蛇也不一定是 snake,serpent 也是蛇的意思。 binwalk -e /Users/xxx/Downloads/snake/snake.jpgbinwalk 提取 key 中有 base64 编码,解密 图源自BUUCTF:snake_buuctf snake-CSDN博客 结果是 anaconda,还有…

Docker 容器网络:C++ 客户端 — 服务器应用程序。

一、说明 在下面的文章中, 将向您概述 docker 容器之间的通信。docker 通信的验证将通过运行 C 客户端-服务器应用程序和标准“ping”命令来执行。将构建并运行两个单独的 Docker 映像。 由于我会关注 docker 网络方面,因此不会提供 C 详细信息。…

30s学会RecyclerView创建动态列表

详细学习请参考官网 使用 RecyclerView 创建动态列表 | Android 开发者 | Android Developers (google.cn) 1.RecyclerView定义及其构造 少废话,就是一个视图控件,就像你刷小红书,东一块西一块很丝滑地滑动 就是 RecyclerView 如下图&a…