dubbo源码—service export
在应用编写好服务并进行之后,dubbo负责将服务export出去,dubbo export服务的时候主要做了以下几件事:
- 将服务export到本地(根据scope的配置)
- 创建Invoker(启动本地NettyServer,监听指定端口,等待请求)
- 注册provider的信息到registry,供consumer发现并订阅服务
- 订阅registry中的configurator节点,可以动态更改部分provider的配置
暴露服务的配置方式有:
- 直接通过API方式
- 通过xml配置
- 通过注解
ServiceBean加载和初始化
以常用的xml配置为例,前面说了dubbo的xml自定义标签最后都是将对应的bean注入容器中,<dubbo:service /> 对应的就是ServiceBean,service暴露服务就在spring初始化ServiceBean的时候
<dubbo:service interface="com.test.service.TestDubboService" ref="testDubboServiceImpl"/>
dubbo解析xml会将对应的bean—ServiceBean注入到spring容器中,由于解析xml的时候配置的bean是非lazyInit的,所以在spring容器初始化完成之后,会初始化所有非lazyInit的bean。
在spring容器初始化后,会广播ContextRefreshedEvent事件通知,ServiceBean实现了ApplicationListener,在收到该事件之后调用export方法
// AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 里面会广播ContextRefreshedEvent事件
finishRefresh();
}
// ServiceBean
public void onApplicationEvent(ApplicationEvent event) {
// 在容器初始化完成之后收到ContextRefreshedEvent事件,开始export服务
if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
if (isDelay() && ! isExported() && ! isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
}
服务export从ServiceConfig#export开始
- export:判断是否是延迟启动,如果是延迟启动则启动守护线程,sleep指定时间之后再调用doExport,否则直接调用
- doExport:主要工作是检查并配置
- 初始化application、registries、monitor等配置
- 判断是否是泛化调用,如果不是,判断interface和ref是否合法
- 检查并配置application、registries、protocols、ServiceConfig本身,找对应配置类属性的set方法,依次从System.getProperty(-D参数指定,或者set进去的配置)、dubbo.properties.file参数执行的配置文件文件中查找对应的属性,然后调用set 方法配置
- 检查是否有stub和mock配置,如果有配置,判断配置是否合法。如果有stub配置:判断stub类是否有该服务interface类型的构造方法;如果有mock配置:如果直接是"return"表达式,parse返回的value是否合法,否则需要判断mockClass是否有无参的构造方法
- loadRegistries:加载所有的registries,可能会有多个注册中心,查找所有的registries配置并返回符合条件的
- 针对每一个registry配置,从applicationConfig、registryConfig获取参数拼装registryUrl
- 条件是:如果是provider则register不能配置为false(可以不配置,如果配置了必须为true);如果不是provider,subscribe不能配置为false(可以不配置,如果配置了必须为true)。
- doExportUrls:由于dubbo支持多个协议,所以dubbo针对每一种协议都会在每一个注册中心注册一遍
- doExportUrlsFor1Protocol:根据配置来拼装URL,在export的整个过程中靠URL来传递配置
- 获取配置的协议名称,如果没有配置协议名称,则使用默认协议:dubbo
- 获取配置的ip:port,如果port没有配置从默认端口20880开始依次向后寻找可用的port,如果port配置为-1表示随机选取一个port
- 从application、module、provider、ptotocol等获取配置,将这些配置加入到map中将来用来生成URL
- 判断是否有dubbo:argument配置,将对应的配置也加入map
- 是否是泛化(Generic)调用,如果没有则判断是否有method级的配置
- 是否是injvm的调用,如果是,则不需要注册到注册中心
- 根据前面host:port、protocolName、map构造URL
- 判断scope的配置,为none表示不暴露服务,配置为remote则export到local和remote,如果配置为local则只export到local
export服务到本地
如果scope没有配置或者配置local、remote,dubbo会将服务export到本地,意思就是:将服务以injvm协议export出去,如果是同一个jvm的应用可以直接通过jvm发起调用,而不需要通过网络发起远程调用。
export到本地主要做了以下几件事:
- 将url的协议配置为jvm,host:port配置为127.0.0.1:0
- 构造filter链,虽然是本地export,但是会经过定义好的filter
- 构造InjvmExporter
创建Invoker
如果scope没有配置或者配置remote,dubbo会创建invoker,创建invoker的时候会启动NettyServer,监听指定的端口等待consumer请求。在dubbo中provider和consumer端都会有Invoker,实现的是同一个接口,但是不同的实现,invoker的意义就是服务的代理,provider侧的invoker就是提供服务的可执行体,在netty接收到请求之后会通过invoker来处理,最后调用目标服务。
创建invoker并启动NettyServer的调用堆栈

export的主要过程是:
- 创建Invoker,proxyFactory.getInvoker
- 创建filter链,ProtocolFilterWrapper#buildInvokerChain
- 调用配置的exporter的listener,ListenerExporterWrapper#ListenerExporterWrapper
- 启动NettyServer,DubboProtocol#openServer
filter和listener是可扩展的,可以自己实现filter和listener,按照SPI方式配置好,dubbo会自动加载。
注册到注册中心并订阅
前面只是完成service的启动并具备可被请求的状态,但是dubbo作为一个支持服务自发现的框架,还会把provider的信息注册到registry,并且订阅configurators。
注册的调用堆栈是

注册和订阅主要逻辑在RegistryProtocol#export
- 启动NettyServer
- 注册providerUrl
- 订阅configurators
registry就是一个目录服务,注册的过程也就是创建对应的目录,并订阅关心的目录变化。provider会在registry中创建类似如下的目录结构

其中provider注册的url为,会创建com.foo.BarService、provider和providerUrl节点
dubbo/com.test.service.TestDubboService/providers/dubbo%3A%2F%2F192.168.0.102%3A20880%2Fcom.test.service.TestDubboService%3Fapplication%3Dcom.test.demo%26default.export%3Dtrue%26export%3Dtrue%26generic%3Dfalse%26interface%3Dcom.test.service.TestDubboService%26pid%3D45599%26side%3Dprovider%26timestamp%3D1515313385792
接下来会创建并订阅configurators节点,订阅的意思就是监听configurators及其子节点,创建configurators的时候会添加listener,provider端监听configurators的listener是:
com.alibaba.dubbo.registry.integration.RegistryProtocol.OverrideListener#notify
在治理中心中修改provider的配置的时候,注册中心会通知监听的listener,provider会进行相关配置。
总结
export服务是dubbo关键路径中的第一步,此时dubbo已经具备了被consumer自动发现并调用的条件,接下来就是consumer发现服务。
dubbo源码—service export的更多相关文章
- dubbo源码—Service Invoke
dubbo的远程调用过程是怎么样的? dubbo远程过程调用经过了那些处理? 发起远程调用的时候究竟传了什么数据给provider? 要解决这些问题,欢迎一起探讨走进dubbo源码栏目. 在servi ...
- dubbo源码—service reference
service reference 在编写好服务之后,dubbo会将服务export出去,这个时候就可以编写consumer来调用这个服务了.dubbo作为一个rpc框架,使用者使用远程服务和使用本地 ...
- dubbo源码—Service Reply
dubbo通过netty将请求发送到provider的时候,provider之前已经启动好的NettyServer监听指定端口的时候会收到来自consumer的请求,将通过网络发送来的二进制编码成Re ...
- dubbo源码分析3-service bean的创建与发布
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- dubbo源码之四——服务发布二
dubbo版本:2.5.4 2. 服务提供者暴露一个服务的详细过程 上图是服务提供者暴露服务的主过程: 首先ServiceConfig类拿到对外提供服务的实际类ref(如:HelloWorldImpl ...
- Dubbo源码学习--服务是如何发布的
相关文章: Dubbo源码学习--服务是如何发布的 Dubbo源码学习--服务是如何引用的 ServiceBean ServiceBean 实现ApplicationListener接口监听Conte ...
- Dubbo源码学习--服务发布(ServiceBean、ServiceConfig)
前面讲过Dubbo SPI拓展机制,通过ExtensionLoader实现可插拔加载拓展,本节将接着分析Dubbo的服务发布过程. 以源码中dubbo-demo模块作为切入口一步步走进Dubbo源码. ...
- dubbo源码—dubbo简介
dubbo是一个RPC框架,应用方像使用本地service一样使用dubbo service.dubbo体系架构 上图中的角色: 最重要的是consumer.registry和provider con ...
- Dubbo源码-从HelloWorld开始
Dubbo简介 Dubbo,相信做后端的同学应该都用过,或者有所耳闻.没错,我就是那个有所耳闻中的一员. 公司在好几年前实现了一套自己的RPC框架,所以也就没有机会使用市面上琳琅满目的RPC框架产品. ...
随机推荐
- 关于网页授权的两种scope的区别说明
关于网页授权的两种scope的区别说明 1.以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的.用户感知的就是直接进入了回 ...
- 游标遍历所有数据库循环执行修改数据库的sql命令
MSSQL数据库服务器上有很多类似的数据库,需要将这些数据库统一修改其中的某些表或者某些命令,那么就会想到用游标来遍历. 先来说思路: 1,首先需要查询出所有的数据库: select [name] f ...
- NGUI_概述
序言:这是张三疯第一次开始NGUI插件的学习,刚开始学习,肯定有很多漏洞,后期会及时的补上的. 希望大家可以见谅,希望大佬多多指教. 一.什么是NGUI: NGUI是严格遵循KISS原则并用C#编写的 ...
- 小白的Python之路 day2 字符串操作 , 字典操作
1. 字符串操作 特性:不可修改 name.capitalize() 首字母大写 name.casefold() 大写全部变小写 name.center(50,"-") 输出 '- ...
- springboot(一)
1,使用springboot开发需要以下配置: : Maven | Gradle | Ant | Starters code工具:IDE | Packaged | Maven | Gradle 系统要 ...
- And【sql语句之为何用and一个字段两个值得不到表中的数据】
一.[一个表的一个字段的多个条件用and连接] 用and是查不到值的, and是多个条件同时成立, 也就是一个字段是不能同时等于两个值的. '; 二[相同两个表的两个相同字段的查询用and连接] '; ...
- Python笔记·第六章——集合 (set) 的增删改查及 copy()方法
简介: 集合是无序的,不重复的数据集合,它里面的元素是可哈希的(不可变类型),但是集合本身是不可哈希(所以集合做不了字典的键)的.以下是集合最重要的两点: 1.去重,把一个列表变成集合,就自动去重了. ...
- 进程组与会话 Linux Process Groups and Sessions
在类Unix系统中,用户通常会跟各种相关的进程打交道.虽然在登录的时候只有一个终端进程(用户对应的登录shell ,通过这个shell启动各种程序和服务),但通常不久以后就会产生许多相关的进程,例如进 ...
- 具体解释Java虚拟机类载入
概述 在Java语言里面,类型的载入.连接和初始化过程都是在程序运行期间完毕的.虚拟机把描写叙述类的数据从Class文件或其他地方载入到内存,并对数据进行校验.转换解析和初始化,终于形成能够被虚拟机直 ...
- EventBus猜想 ----手把手带你自己实现一个EventBus
本文是什么 本文是一篇怀着推測角度学习一个未知东西(EventBus)的文章. 先推測EventBus是怎样实现的. 依据推測去模仿他的实现. 查看源代码.验证猜想. 更深入的去理解他. 转载请注明出 ...