dubbo源码分析二:服务发布
本文将深入分析dubbo的服务发布涉及到的流程及主要类的代码。首先,我们先从类的关系图来看一下dubbo发布服务涉及到的相关类。
1.类图

上图展示了部分服务发布过程中需要使用到的类和接口,其中:
spring适配涉及到的类:DubboNamespaceHandler、DubboBeanDefinitionParser、ServiceBean;
配置信息存储:ServicdConfig、RegistryConfig、MonitorConfig、ProtocolConfig、ProviderConfig等;
应用协议:Protocol、DubboProtocol、HessianProtocol、ThriftProtocol、RmiProtocol、AbstractProxyProtocol、AbstractProtocol等;
Server相关:Exchanger、HeaderExchanger、ExchangeServer、HeaderExchangeServer、Transporters、Transporter、NettyTransporter、NettyServer等;
2.时序图
我们通过时序图来分析一下在发布服务的过程中,上面的类是如何串联在一起的:
a.spring容器通过DubboBeanDefinitionParser类的对象来解析xml文件中的标签,生成ServiceConfig等配置对象;
b.ServiceConfig的export()等发布服务的方法被调用;
c.通过spi机制确定Protocol接口的实现对象为DubboProtocol的对象,调用它的openServer()等方法;
d.通过spi机制确定Transporter接口的实现对象为NettyTransporter,调用它的bind()方法;
e.调用NettyServer类,启动netty服务,绑定端口。

3.核心代码解析
a.DubboProtocol
public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl();//获取url信息
// export service.
String key = serviceKey(url);//产生与发布的接口映射的key ,格式例如:com.alibaba.dubbo.demo.DemoService:20882
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);//创建DubboExporter对象
exporterMap.put(key, exporter);//缓存此对象
//export an stub service for dispaching event
Boolean isStubSupportEvent = url.getParameter(Constants.STUB_EVENT_KEY,Constants.DEFAULT_STUB_EVENT);
Boolean isCallbackservice = url.getParameter(Constants.IS_CALLBACK_SERVICE, false);
if (isStubSupportEvent && !isCallbackservice){
String stubServiceMethods = url.getParameter(Constants.STUB_EVENT_METHODS_KEY);
if (stubServiceMethods == null || stubServiceMethods.length() == 0 ){
if (logger.isWarnEnabled()){
logger.warn(new IllegalStateException("consumer [" +url.getParameter(Constants.INTERFACE_KEY) +
"], has set stubproxy support event ,but no stub methods founded."));
}
} else {
stubServiceMethodsMap.put(url.getServiceKey(), stubServiceMethods);
}
}
openServer(url);//打开服务
return exporter;
}
private void openServer(URL url) {
// find server.
String key = url.getAddress();
//client 也可以暴露一个只有server可以调用的服务。
boolean isServer = url.getParameter(Constants.IS_SERVER_KEY,true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
serverMap.put(key, createServer(url));//创建新的服务
} else {
//server支持reset,配合override功能使用
server.reset(url);
}
}
}
private ExchangeServer createServer(URL url) {
//默认开启server关闭时发送readonly事件
url = url.addParameterIfAbsent(Constants.CHANNEL_READONLYEVENT_SENT_KEY, Boolean.TRUE.toString());
//默认开启heartbeat
url = url.addParameterIfAbsent(Constants.HEARTBEAT_KEY, String.valueOf(Constants.DEFAULT_HEARTBEAT));
String str = url.getParameter(Constants.SERVER_KEY, Constants.DEFAULT_REMOTING_SERVER);
if (str != null && str.length() > 0 && ! ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str))
throw new RpcException("Unsupported server type: " + str + ", url: " + url);
url = url.addParameter(Constants.CODEC_KEY, Version.isCompatibleVersion() ? COMPATIBLE_CODEC_NAME : DubboCodec.NAME);
ExchangeServer server;
try {
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
}
str = url.getParameter(Constants.CLIENT_KEY);
if (str != null && str.length() > 0) {
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return server;
}
b.NettyServer
protected void doOpen() throws Throwable {
NettyHelper.setNettyLoggerFactory();
ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));//boss线程池
ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));//工作线程池
ChannelFactory channelFactory = new NioServerSocketChannelFactory(boss, worker, getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS));
bootstrap = new ServerBootstrap(channelFactory);//服务启动类
final NettyHandler nettyHandler = new NettyHandler(getUrl(), this);
channels = nettyHandler.getChannels();
// https://issues.jboss.org/browse/NETTY-365
// https://issues.jboss.org/browse/NETTY-379
// final Timer timer = new HashedWheelTimer(new NamedThreadFactory("NettyIdleTimer", true));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec() ,getUrl(), NettyServer.this);
ChannelPipeline pipeline = Channels.pipeline();
/*int idleTimeout = getIdleTimeout();
if (idleTimeout > 10000) {
pipeline.addLast("timer", new IdleStateHandler(timer, idleTimeout / 1000, 0, 0));
}*/
pipeline.addLast("decoder", adapter.getDecoder());//增加解码器
pipeline.addLast("encoder", adapter.getEncoder());//增加编码器
pipeline.addLast("handler", nettyHandler);//业务处理类
return pipeline;
}
});
// bind
channel = bootstrap.bind(getBindAddress());
}
dubbo源码分析二:服务发布的更多相关文章
- Dubbo源码分析系列---服务的发布
摘要: 通过解析配置文件,将xml定义的Bean解析并实例化,(涉及重要的类:ServiceBean.RegistryConfig[注册中心配置].ProtocolConfig[协议配置].Appli ...
- dubbo 源码学习1 服务发布机制
1.源码版本:2.6.1 源码demo中采用的是xml式的发布方式,在dubbo的 DubboNamespaceHandler 中定义了Spring Framework 的扩展标签,即 <dub ...
- dubbo源码分析13——服务本地暴露 exportLocal(url)
dubbo服务的本地暴露,显然是针对当服务消费者和服务提供者都在同一个jvm的进程内这种场景 .通常是发生在服务之间的调用的情况下.一种情况就是A服务调用B服务的情况,如果A服务和B服务都是在一个线程 ...
- dubbo源码分析8——服务暴露概述
从上文中可知,com.alibaba.dubbo.config.spring.ServiceBean类是负责解析<dubbo:service/>的配置的,下面是它的类图 从类图上可知它继承 ...
- dubbo源码分析10——服务暴露1_export()方法分析
ServiceConfig类中的export()方法,是dubbo服务暴露的入口方法,被触发的时机有两个: 1. spring容器初始化完成所有的bean实例后,通过事件机制触发 2. 实现Initi ...
- dubbo源码分析12——服务暴露3_doExportUrls()方法分析
本文紧接上文,doExportUrls()方法位于ServiceConfig类中,代码入口如下: private void doExportUrls() { List<URL> regis ...
- dubbo源码分析11——服务暴露2_doExport()方法分析
protected synchronized void doExport() { //如果是已经解除暴露的接口则抛出异常 if (unexported) { throw new IllegalStat ...
- Dubbo 源码分析 - 服务调用过程
注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...
- dubbo源码分析2-reference bean发起服务方法调用
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
随机推荐
- 『重构--改善既有代码的设计』读书笔记----Introduce Local Extension
同Introduce Foreign Method一样,很多时候你不能修改编辑原始类,你需要为这些服务类增加一些额外的函数,但你没有这个权限或者入口.如果你只需要一个或者两个外加函数那么你可以放心的使 ...
- mysqldump: command not found问题解决
首先得知道mysql命令或mysqldump命令的完整路径,可以使用find命令查找除非你知道mysql安装路径可以略过这一步. find / -name mysql -print 例如我的mysql ...
- java 下载文件 内容为空。
检查下是不是io流没有关闭,记得关闭所有流.
- Extjs4.2.1学习笔记[更新]
心血来潮准备学习一下Extjs,就从官方网站http://extjs.org.cn/下载了最新版本4.2.1,开始从头学习,记一下笔记,让自己能够持之以恒. 先说一下基本文件类库引用吧, 每个项目一开 ...
- MongoDB 复制集模式Replica Sets
1.概述 复制集是一个带有故障转移的主从集群.是从现有的主从模式演变而来,增加了自动故障转移和节点成员自动恢复. 复制集模式中没有固定的主结点,在启动后,多个服务节点间将自动选举 产生一个主结点.该主 ...
- PHP 设计模式之适配器模式
<?php //[主要角色] //目标(Target)角色:定义客户端使用的与特定领域相关的接口,这也就是我们所期待得到的 //源(Adaptee)角色:需要进行适配的接口 //适配器(Adap ...
- South入门教程
对于django自带的syncdb同步models和数据库的缺陷,所以我选择第三方的工具South. 1.安装South:pip install South 2.South设置: 把 south 加到 ...
- laravel框架——线上环境错误总结
除了根目录,其他目录访问全是Not Found
- BZOJ 1070 修车
Description 同一时刻有\(N\)位车主带着他们的爱车来到了汽车维修中心.维修中心共有\(M\)位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这\(M\)位技术 ...
- Unity3d 项目管理 版本管理
Unity3d中项目管理 版本管理 如果在提交文件的时候发现提示有"先更新,再提交的"提示的时候,这是因为,A提交了一个版本文件,版本是13,那么你还在修改版本为12的文件 ...