Dubbo源码分析:dubbo与spring融合

撸了今年阿里、腾讯和美团的面试,我有一个重要发现…….

作者:backend

出处:https://blog.csdn.net/u010013573/article/category/8462451


概述

  • Dubbo框架主要是用于分布式系统中服务之间的远程调用。而分布式系统中的每个服务一般为采用spring框架搭建,通过spring容器管理beans,通过spring mvc提供restful接口,在service层进行业务逻辑处理。而不管是服务消费者引用的bean,还是服务提供者需要对外提供服务、进行注册的bean,都需要一种机制来触发其进行初始化,生成JVM堆的一个对象实例,同时由spring容器管理,可以通过@Autowired进行注入,从而可以在运行时进行调用。
  • 在dubbo源码结构中,主要在dubbo-config模块进行服务建模。具体为在dubbo-config-api子模块对服务进行各粒度的建模,依次为应用、提供者、消费者、注册中心、服务模块、服务提供类和引用类、方法、方法参数;在dubbo-config-spring子模块将消费者配置引用的服务,提供者配置对外提供调用的服务分别融合到相应项目的spring容器中,从而可以在service层通过@Autowired的机制进行注入。
    201907191006_1.png

配置解析规则定义

  1. 在dubbo.xsd定义dubbo相关标签
    201907191006_2.png
  2. 在dubbo.schemas定义标签的位置location
    201907191006_3.png
  3. dubbo标签处理器器配置:在spring.handlers中定义了dubbo的命名空间和标签处理器DubboNamespaceHandler的对应关系,即当遇到dubbo标签的时候,使用DubboNamespaceHandler进行处理,解析生成beanDefinition,其中DubboNamespaceHandler继承于NamespaceHandlerSupport。
    201907191006_4.png
    201907191006_5.png

解析配置文件并生成beanDefinition

在spring扫描和解析xml文件遇到dubbo标签的时候,会使用DubboNamespaceHandler进行标签处理。

  1. DubboNamespaceHandler:自定义了BubboBeanDefinitionParser,使用相应的解析器,解析配置文件的标签,并转换成相应的beanDefinition。
    201907191005_6.png
    201907191005_7.png
  2. 通过registerBeanDefinitionParser将标签名称和解析器的对应关系注册到NamespaceHandlerSupport中的parsers中,从而在spring扫描和解析xml文件遇到对应的dubbo标签时,会使用相应的DubboBeanDefinitionParser进行标签解析,生成beanDefinition。通过registerBeanDefinitionParser将标签名称和解析器的对应关系注册到NamespaceHandlerSupport中的parsers中,从而在spring扫描和解析xml文件遇到对应的dubbo标签时,会使用相应的DubboBeanDefinitionParser进行标签解析,生成beanDefinition。
    201907191005_8.png
    如果是使用注解而不是配置文件,则使用AnnotationBeanDefinitionParser。
    201907191005_9.png

服务提供者提供的服务Service:ServiceBean

201907191005_10.png

  1. ServiceBean实现ApplicationListener接口,泛型参数为ContextRefreshedEvent,从而在spring容器启动或重启时会触发。
    201907191005_11.png
  2. ServiceBean继承于ServiceConfig,调用ServiceConfig的export方法,该方法会产生该service的Invoker,即通过该Invoker调用serviceImpl的方法,其中invoker是从该service的具体实现代理ref获取:
    201907191005_12.png
    包含setRef方法,通过ExtensionLoader注入。
    201907191005_13.png
  3. 由之前的文章分析可知,export最终会调用RegistryProtocol的export方法完成服务导出,注册到注册中心,同时会调用doLocalExport,在提供者本地生成消费者请求处理invoker。具体为根据URL确定所使用的、对应与dubbo-rpc模块的具体rpc协议protocol,如DubboProtocol,调用protocol.export创建export对象和实际的监听URL和请求处理器,DubboProtocol请求处理器的远程通讯由dubbo-remoting模块实现,源码如下:
    201907191005_14.png
    201907191005_15.png
    其中invoker为2中,注册导出服务时创建的invoker。

服务消费者引用的服务Reference:ReferenceBean

201907191005_16.png

  1. 在解析dubbo:reference时,会产生ReferenceBean的实例。ReferenceBean实现了spring的FactoryBean接口,故spring在注入bean时,在程序使用如@Autowired时,会调用getObject方法,获取对象实例,如果是singleton类,则放到spring单实例缓存池。
  2. ReferenceBean继承于ReferenceConfig,getObject调用ReferenceConfig的get方法,其中get为使用synchronized修饰,保证只初始化一次:
    201907191005_17.png
    init方法底层实现核心源码如下:
    201907191005_18.png
    其中map为该对象实例的属性和属性值,通过createProxy创建消费者调用的代理对象。createProxy的核心源码实现如下:
    (1)refprotocol:根据URL的protocol获取到dubbo-rpc模块的protocol实现,调用refprotocol.refer获取对应的消费者端的调用;通过这个代理来对服务提供者或者说服务端发起RPC请求;
    (2)cluster.join:如果包含多个注册中心,则调用cluster.join进行负载均衡获取一个调用;
    (3)proxyFactory.getProxy(invoker):获取最终的消费者调用代理,代理提供了一个模板,最终的调用逻辑是定义在对应的Invoker的doInvoke方法,如DubboInvoker,在doInvoker中再调用dubbo-remoting模块的client进行远程通讯。
    201907191005_19.png

DubboBootstrap注册spring shutdownHook

这个是在dubbo被apache孵化后,加入的。包括注册spring shutdownhook和export Service,但是export Service目前没有具体实现,还是在注册ServiceBean创建bean实例时,export。

  1. 通过context-param的方式将dubbo引入到宿主应用中
    web-fragment.xml文件:相当于web.xml的一个小片段,通过合并这个文件到web.xml,从而在宿主应用启动时,初始化DubboApplicationContextInitializer。
    201907191005_20.png
  2. 监听spring框架启动:在DubboApplicationContextInitializer初始化时,将DubboApplicationListener作为监听器,监听宿主应用的启动。
    201907191005_21.png
    DubboApplicationListener监听宿主应用的启动和关闭,调用DubboBootstrap进行dubbo框架的启动和关闭。
    201907191005_22.png
    /**
     * A bootstrap class to easily start and stop Dubbo via programmatic API.
     * The bootstrap class will be responsible to cleanup the resources during stop.
     */
    public class DubboBootstrap
    核心方法
    public void start() {
            if (registerShutdownHookOnStart) {
                registerShutdownHook();
            } else {
                // DubboShutdown hook has been registered in AbstractConfig,
                // we need to remove it explicitly
                removeShutdownHook();
            }
            for (ServiceConfig serviceConfig: serviceConfigList) {
                serviceConfig.export();
            }
        }

        public void stop() {
            for (ServiceConfig serviceConfig: serviceConfigList) {
                serviceConfig.unexport();
            }
            shutdownHook.destroyAll();
            if (registerShutdownHookOnStart) {
                removeShutdownHook();
            }
        }

赞(0) 打赏

如未加特殊说明,此网站文章均为原创,转载必须注明出处。Java 技术驿站 » Dubbo源码分析:dubbo与spring融合
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

关注【Java 技术驿站】公众号,每天早上 8:10 为你推送一篇技术文章

扫描二维码关注我!


关注【Java 技术驿站】公众号 回复 “VIP”,获取 VIP 地址永久关闭弹出窗口

免费获取资源

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏