Dubbo学习-源码学习

Dubbo概述

dubbo框架提供多协议远程调用,服务提供方可以是分布式部署。dubbo框架可以很简单的帮我们实现微服务。

此处援引官网上图片

dubbo分为客户端和服务提供方

服务方将服务注册到注册中心

客户端从注册中心获取已注册服务访问方式

客户端通过指定协议访问服务提供方

根据dubbo架构,源码分析我们主要切入点是:

  1. dubbo配置如何生效
  2. 客户端如何调用服务
  3. 注册的服务如何保证被调用到
  4. dubbo远程调用的协议如何工作

针对以上我们来分析Dubbo源码:

Dubbo源码是maven管理,工程主要由dubbo-config,dubbo-container,dubbo-filter,dubbo-monitor,dubbo-registry,dubbo-remoting,dubbo-rpc,dubbo-serialization组成。

  • dubbo-config :dubbo配置文件相关模块
  • dubbo-container :dubbo依赖的上下文
  • dubbo-filter : dubbo支持的请求过滤器
  • dubbo-monitor : dubbo监控管理模块
  • dubbo-registry : dubbo使用注册中心相关的模块
  • dubbo-remoting : dubbo整个远程交互框架,如何将通道、序列化、通信载体有机整合
  • dubbo-rpc : dubbo远程调用协议实现。
  • dubbo-serialization : 远程通信中序列化实现

dubbo配置加载

dubbo配置是以松耦合的方式嵌入到spring里面,因此说到dubbo配置加载就必然和spring扯不开关系。

从dubbo配置文件的命名空间说起,我们通常在配置dubbo服务时要在spring配置基础上添加dubbo的命名空间(xmlns)和模板:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://code.alibabatech.com/schema/dubbo
        http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

  

xmlns:dubbo的值指定了dubbo配置命名空间。spring中不同的命名空间对应不同的配置解析器,那么dubbo的命名空间http://code.alibabatech.com/schema/dubbo也就对应着自己的解析器。spring维护着命名空间和对应解析器的关系,这些对应关系包括spring内置的和第三方定制关系

spring命名空间

spring启动中解析dubbo xml文件时首先获取跟节点中的所有xmlns值,根据配置的命名空间从命名空间管理器中获取该空间对应的解析器对象

命名空间管理器会从classpath下META-INF/下加载并解析所有的所有spring.handlers命名的文件,该文件以键值对配置了命名空间和对应解析器。

dubbo的命名spring.handler配置如下:

http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler

路径:META-INF/dubbo/spring.handler

如此,spring在加载dubbo配置时会调用dubbo命名空间解析器DubboNamespaceHandler来解析配置文件,dubbo的入口也就是DubboNamespaceHandler。

dubbo配置解析处理器(DubboNamespaceHandler)

dubbo配置解析处理器就是命名空间配置的com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler,该处理器作为dubbo对spring的扩展完成dubbo自定义的配置解析工作。spring的命名空间处理器扩展点是:org.springframework.beans.factory.xml.NamespaceHandlerSupport,DubboNamespaceHandler完成dubbo内部所有解析器初始和加载。解析器包括application节点解析、module节点解析、registry、monitor、provider、consumer、protocol、service、reference、annotation。

这些解析器初始化代码如下:

 1 public void init() {
 2         registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
 3         registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
 4         registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
 5         registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
 6         registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
 7         registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
 8         registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
 9         registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
10         registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
11         registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
12     }

DubboNamespaceHandler做了什么

spring加载配置文件过程中,读取到一个xml节点时,会将节点信息传递给DubboNamespaceHandler,handler获取节点的LocalName(在一个命名空间下去掉前缀剩下的节点名          称),根据名称从DubboNamespaceHandler获取对应的Parser,如:LocalName是application,就会获取到Handler初始化时注册的application对应的                                                    DubboBeanDefinitionParser对象,并调用该解析器的parse方法将节点转换成spring的RootBeanDefinition对象,对象保存了创建一个bean对象所需的所有信 息。

Dubbo服务(ServiceBean)

通过registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));注册的DubboBeanDefinitionParser

创建出的RootBeanDefinition最终被spring实例化成ServiceBean,ServiceBean即Dubbo实际的服务实例。实例化结束后,ServiceBean会从spring容器中获取配置的Provider信         息、application、module、registry、monitor、protocol等配置信息并设置到ServiceBean,设置完成后将服务自身暴露出去,如果本次暴露失败或者没有暴露,则在spring容器启       动完成后会再进行一次暴露。

服务暴露

服务暴露通过调用ServiceBean的export方法,通过注册中心,最终将服务实例以指定的协议暴露给调用方。

准备暴露路径

服务暴露前需要组织自己的访问路径和协议信息,只有有了这些信息,才能确定以何种协议被访问,以及通过什么路径被访问。组织访问信息的方法是服务自身的doExportUrls

ServiceConfig.doExportUrls()

1     private void doExportUrls() {
2         List<URL> registryURLs = loadRegistries(true);
3         for (ProtocolConfig protocolConfig : protocols) {
4             doExportUrlsFor1Protocol(protocolConfig, registryURLs);
5         }
6     }

该方法调用了doExportUrlsFor1Protocol方法将协议和注册路径具体的组装起来,形成dubbo的访问路径,将访问路径包装秤可悲远程调用的调用器invoker。

invoker的生成代码如下:

 1             //如果配置不是local则暴露为远程服务.(配置为local,则表示只暴露本地服务)
 2             if (! Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope) ){
 3                 if (logger.isInfoEnabled()) {
 4                     logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
 5                 }
 6                 if (registryURLs != null && registryURLs.size() > 0
 7                         && url.getParameter("register", true)) {
 8                     for (URL registryURL : registryURLs) {
 9                         url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
10                         URL monitorUrl = loadMonitor(registryURL);
11                         if (monitorUrl != null) {
12                             url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
13                         }
14                         if (logger.isInfoEnabled()) {
15                             logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
16                         }
17                         Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
18
19                         Exporter<?> exporter = protocol.export(invoker);
20                         exporters.add(exporter);
21                     }
22                 } else {
23                     Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
24
25                     Exporter<?> exporter = protocol.export(invoker);
26                     exporters.add(exporter);
27                 }
28             }
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));参数ref指向的是dubbo:service配置中ref中指定的服务对象,interfaceClass是该服务的接口,第三个参数则是该服务的访问路径。
Exporter<?> exporter = protocol.export(invoker);   // 最终将invoker暴露

原文地址:https://www.cnblogs.com/liwutao/p/8809469.html

时间: 2024-11-10 02:45:30

Dubbo学习-源码学习的相关文章

dubbo源码学习(一)基础知识及使用的相关技术

初学dubbo的源码,只做尝试性的去学习,做为自己学习的一个记录,各位看官如果觉得写的有错误或理解的不对,请在留言区告诉我,互相学习.本人能力有限,有大神进入 时请指点. Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合),我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配置就能够实现分布式服务调用,也就

dubbo源码学习(四)初始化过程细节:解析服务

初学dubbo的源码,只做尝试性的去学习,做为自己学习的一个记录,各位看官如果觉得写的有错误或理解的不对,请在留言区告诉我,互相学习.本人能力有限,有大神进入 时请指点. 前面大概介绍了一下关于学习dubbo源码的一些基本知识,今天将真正去看dubbo内部的实现过程,看dubbo的源码前我先把dubbo的用户指南和开发指指南大概的看了一遍,然后从上面找到相应的切入点去看源码,今天将介绍的是dubbo的初始化解析bean的过程.从之前使用过dubbo一些经验,加上http://dubbo.io/的

dubbo源码学习(五)dubbo暴露服务的过程

初学dubbo的源码,只做尝试性的去学习,做为自己学习的一个记录,各位看官如果觉得写的有错误或理解的不对,请在留言区告诉我,互相学习.本人能力有限,有大神进入 时请指点. dubbo采用的nio异步的通信,通信协议默认为 netty,当然也可以选择 mina,grizzy.在服务端(provider)在启动时主要是开启netty监听,在zookeeper上注册服务节点,处理消费者请求,返回处理后的消息给消费者,消费者使用服务时主要是订阅服务的节点,监听zookeeper节点目录,服务端的变化时z

Dubbo源码学习--优雅停机原理及在SpringBoot中遇到的问题

相关文章: Dubbo源码学习文章目录 前言 主要是前一阵子换了工作,第一个任务就是解决目前团队在 Dubbo 停机时产生的问题,同时最近又看了一下 Dubbo 的源码,想重新写一下 Dubbo 相关的文章. 优雅停机原理 对于一个 java 应用,如果想在关闭应用时,执行一些释放资源的操作一般是通过注册一个 ShutDownHook ,当关闭应用时,不是调用 kill -9 命令来直接终止应用,而是通过调用 kill -15 命令来触发这个 ShutDownHook 进行停机前的释放资源操作.

Dubbo源码学习(二)

@Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Adaptive { String[] value() default {}; } @Adapt

跟大家聊聊我们为什么要学习源码?学习源码对我们有用吗?(源码感悟)

1 前言 由于现在微服务很流行,越来越多企业采用了SpringCloud微服务架构,而SpringBoot则是快速构建微服务项目的利器.于是源码笔记以此为切入点,将SpringBoot作为我们源码分析的第一个开源项目,之后还会对更多开源项目进行源码分析.要进行源码分析,笔者结合自身经历来跟大家聊聊我们为什么要学习源码这个话题,大家一起探讨学习. 我们程序员在开发代码时每天都在使用别人写好的框架,无论你是在使用Spring生态的Spring核心,SpringMVC,SpringBoot和Sprin

FireMonkey 源码学习(5)

(5)UpdateCharRec 该函数的源码分析如下: procedure TTextLayoutNG.UpdateCharRec(const ACanvas: TCanvas; NeedBitmap: Boolean; var NewRec: PCharRec; HasItem: Boolean; const CharDic: TCharDic; const AFont: TFont; const Ch: UCS4Char; const NeedPath: Boolean = False);

jquery源码学习

jQuery 源码学习是对js的能力提升很有帮助的一个方法,废话不说,我们来开始学习啦 我们学习的源码是jquery-2.0.3已经不支持IE6,7,8了,因为可以少学很多hack和兼容的方法. jquery-2.0.3的代码结构如下 首先最外层为一个闭包, 代码执行的最后一句为window.$ = window.jquery = jquery 让闭包中的变量暴露倒全局中. 传参传入window是为了便于压缩 传入undefined是为了undifined被修改,他是window的属性,可以被修

Hadoop源码学习笔记(1) ——第二季开始——找到Main函数及读一读Configure类

Hadoop源码学习笔记(1) ——找到Main函数及读一读Configure类 前面在第一季中,我们简单地研究了下Hadoop是什么,怎么用.在这开源的大牛作品的诱惑下,接下来我们要研究一下它是如何实现的. 提前申明,本人是一直搞.net的,对java略为生疏,所以在学习该作品时,会时不时插入对java的学习,到时也会摆一些上来,包括一下设计模式之类的.欢迎高手指正. 整个学习过程,我们主要通过eclipse来学习,之前已经讲过如何在eclipse中搭建调试环境,这里就不多述了. 在之前源码初