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 {@Beanpublic 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会注入ConfigurationBeanBindingsRegisterregisterBeans(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=dubbodubbo.protocol.port=20880dubbo.protocol.host=0.0.0.02、如果开启了multiple模式,那么可以支持多个dubbo.protocol,比如:dubbo.protocols.p1.name=dubbodubbo.protocols.p1.port=20880dubbo.protocols.p1.host=0.0.0.0dubbo.protocols.p2.name=httpdubbo.protocols.p2.port=8082dubbo.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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux - updatedb 命令

1. 功能 updatedb 命令用来创建或更新slocate命令所必需的数据库文件。updatedb 命令的执行过程较长,因为在执行时它会遍历整个系统的目录树,并将所有的文件信息写入 slocate 数据库文件中。 补充说明:slocate 本身具有一个数据库&#xff…

【PyQt】10 QLineEdit

文章目录 前言一、回显模式(EchoMode)1.1 四种回显模式1.2 代码展示运行结果 二、校验器2.1 代码2.2 运行结果 三、通过掩码限制输入3.1 代码3.2 运行结果 总结 前言 1、QLineEdit 可以输入单行文字 2、回显模式 3、校验器 4、掩码输入 一、回显模式&am…

Linux开发:PAM3 Ubuntu(22.04)安装PAM开发库

Ubuntu22.04默认是不带pam开发库的,需要通过以下命令进行安装 sudo apt install libpam0g-dev 关于PAM的文档可以参考: Ubuntu Manpage: pam - Pluggable Authentication Modules Library 也可以通过man进行查看: man 3 pam 编译程序是需要加…

16进制内存地址——计算机内存地址为什么用16进制?

在计算机底层,内存地址通常以十六进制表示。使用十六进制可以更好地理解和识别内存地址、指针和寄存器等底层系统信息。 谈到内存地址,不可避免引出指针的概念。 变量和数据在内存中是如何存放的呢?我们知道,所谓程序是由计算机&a…

k8s-资源限制与监控 15

资源限制 上传实验所需镜像 Kubernetes采用request和limit两种限制类型来对资源进行分配。 request(资源需求):即运行Pod的节点必须满足运行Pod的最基本需求才能 运行Pod。 limit(资源限额):即运行Pod期间,可能内存使用量会增加&#xff0…

Jupyter Notebook如何在E盘打开

Jupyter Notebook如何在E盘打开 方法1:方法2: 首先打开Anaconda Powershell Prompt, 可以看到默认是C盘。 可以对应着自己的界面输入: 方法1: (base) PS C:\Users\bella> E: (base) PS E:\> jupyter notebook方法2&#x…

[AIGC] Tomcat:一个简单 and 高效的 Java Web 服务器

Tomcat(Tomcat Server)是 Apache 基金会下的一个开源项目,它是一个简单 and 高效的 Java Web 服务器,支持 Servlet 2.5、JSP 2.2 和 EL 2.2 规范。Tomcat 是当今最受欢迎的 Java Web 服务器之一,它在 Java 世界中被广泛…

跳表详解和实现|深挖Redis底层数据结构

文章目录 跳表前言项目代码仓库认识跳表跳表的实现思路跳表性能分析对比平衡树(avl和红黑树)和哈希表使用手册成员变量成员函数构造析构迭代器sizeclearemptyoperatorfindinserterase 跳表细节实现节点定义跳表结构定义构造、析构、拷贝构造和赋值重载si…

人工智能算法:理解其工作原理及其在现实世界中的应用

随着科技的飞速发展,人工智能(AI)已逐渐成为我们生活中不可或缺的一部分。从智能语音助手到自动驾驶汽车,再到医疗诊断系统,人工智能算法正以前所未有的速度改变着我们的世界。本文将带您深入探讨人工智能算法的工作原…

【MySQL】数据库的基础——数据库的介绍、MySQL的介绍和架构、SQL分类、MySQL的基本使用、MySQL的存储引擎

文章目录 MySQL1. 数据库的介绍1.2 主流数据库 2. MySQL的介绍2.1 MySQL架构2.2 SQL分类2.3 MySQL的基本使用2.4 MySQL存储引擎 MySQL 1. 数据库的介绍 数据库(Database,简称DB)是按照数据结构来组织、存储和管理数据的仓库。它是长期存储在计…

uni-app x,一个纯原生的Android App开发工具

uni-app x,下一代uni-app,一个神奇的产品。 用vue语法、uni的组件、api,以及uts语言,编译出了kotlin的app。不再使用js引擎和webview。纯纯的kotlin原生app。 uni-app x,让“跨平台开发性能不如原生”的这条曾广为流…

面试 JavaScript 框架八股文十问十答第四期

面试 JavaScript 框架八股文十问十答第四期 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新! ⭐点赞⭐收藏⭐不迷路!⭐ 1)new操作符的实现…

LLM之LangChain(七)| 使用LangChain,LangSmith实现Prompt工程ToT

如下图所示,LLM仍然是自治代理的backbone,可以通过给LLM增加以下模块来增强LLM功能: Prompter AgentChecker ModuleMemory moduleToT controller 当解决具体问题时,这些模块与LLM进行多轮对话。这是基于LLM的自治代理的典型情况,…

Linux 命令基础

Shell概述 Linux操作系统的Shell作为操作系统的外壳,为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。 Shell是用户和Linux内核之间的接口程序,如果把硬件想象成一个球体的中心,内核围绕在硬件的外层管理着…

无锁序列系列笔记

下面是常见的一些实现方式: 1、借助智能指针来实现。下面是一篇参考博文 2、借助automic使用CAS(Compare And Swap)原子操作, std::atomic_flag,不同于所有 std::atomic 的特化,它保证是免锁的,不提供load()与store(val)操作&…

itextpdf使用:使用PdfReader添加图片水印

gitee参考代码地址:https://gitee.com/wangtianwen1996/cento-practice/tree/master/src/test/java/com/xiaobai/itextpdf 参考文章:https://www.cnblogs.com/wuxu/p/17371780.html 1、生成带有文字的图片 使用java.awt包的相关类生成带文字的图片&…

keil调试出现cannot evaluate新思路

我在用最新的keil时也出现了这个问题,网上说的办法几乎没啥用,包括魔术棒的设置和将变量定义为全局变量,都没用。 这里我使用的是keil5.13,编译器是AC6.21,硬件是STM32F407VET6 可以看到,即使是定义为全局变…

问题:超声波纵波斜入射时,当入射角大于第一临界角小于第二临界角时,在第二介质内只有折射横波。 #微信#经验分享#其他

问题:超声波纵波斜入射时,当入射角大于第一临界角小于第二临界角时,在第二介质内只有折射横波。 参考答案如图所示

QT - 嵌入式快速移植QT记录

QT快速移植指南 本指南旨在提供一个关于如何为特定目标平台快速移植QT应用程序的详细步骤说明。以下内容包含技术背景、配置步骤以及相关命令,帮助开发者有效地将QT应用部署在不同的硬件平台上。 技术背景 QT是一个跨平台的C图形用户界面应用程序开发框架&#x…

力扣94-二叉树的中序遍历

二叉树的中序遍历 题目链接 解题思路 递归解决先遍历左子树访问根节点再遍历右子树 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* …