本文将深入分析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源码分析二:服务发布的更多相关文章

  1. Dubbo源码分析系列---服务的发布

    摘要: 通过解析配置文件,将xml定义的Bean解析并实例化,(涉及重要的类:ServiceBean.RegistryConfig[注册中心配置].ProtocolConfig[协议配置].Appli ...

  2. dubbo 源码学习1 服务发布机制

    1.源码版本:2.6.1 源码demo中采用的是xml式的发布方式,在dubbo的 DubboNamespaceHandler 中定义了Spring Framework 的扩展标签,即 <dub ...

  3. dubbo源码分析13——服务本地暴露 exportLocal(url)

    dubbo服务的本地暴露,显然是针对当服务消费者和服务提供者都在同一个jvm的进程内这种场景 .通常是发生在服务之间的调用的情况下.一种情况就是A服务调用B服务的情况,如果A服务和B服务都是在一个线程 ...

  4. dubbo源码分析8——服务暴露概述

    从上文中可知,com.alibaba.dubbo.config.spring.ServiceBean类是负责解析<dubbo:service/>的配置的,下面是它的类图 从类图上可知它继承 ...

  5. dubbo源码分析10——服务暴露1_export()方法分析

    ServiceConfig类中的export()方法,是dubbo服务暴露的入口方法,被触发的时机有两个: 1. spring容器初始化完成所有的bean实例后,通过事件机制触发 2. 实现Initi ...

  6. dubbo源码分析12——服务暴露3_doExportUrls()方法分析

    本文紧接上文,doExportUrls()方法位于ServiceConfig类中,代码入口如下: private void doExportUrls() { List<URL> regis ...

  7. dubbo源码分析11——服务暴露2_doExport()方法分析

    protected synchronized void doExport() { //如果是已经解除暴露的接口则抛出异常 if (unexported) { throw new IllegalStat ...

  8. Dubbo 源码分析 - 服务调用过程

    注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...

  9. dubbo源码分析2-reference bean发起服务方法调用

    dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...

随机推荐

  1. [转]PHP取整函数:ceil,floor,round,intval的区别详细解析

    我们经常用到的PHP取整函数,主要是:ceil,floor,round,intval. 1.ceil -- 进一法取整 说明float ceil ( float value ) 返回不小于 value ...

  2. 详解函数声明VS函数表达式

    函数声明 比方如下:1.我们以一个完整的语句以function开头,不加任何东西. 2.有一个函数名(add) 3.参数可带可不带(x,y) 4.有一个数体 满足以上要求的我们统称为函数声明! 附加小 ...

  3. python与编码方式

    1.编码方式: ASCII编码:用来表示英文,它使用1个字节表示,其中第一位规定为0,其他7位存储数据,一共可以表示128个字符. 拓展ASCII编码:用于表示更多的欧洲文字,用8个位存储数据,一共可 ...

  4. .net 实例化对象

    定义TestClass,在调用的地方 TestClass a; 如果下面有引用 a.Property,VS会报错,而如果 TestClass a = null; 再次调用的话则不会报错. TestCl ...

  5. 开源中国iOS客户端学习

    开源中国iOS客户端学习 续写前言 <开源中国iOS客户端学习>续写前系列博客    http://blog.csdn.net/column/details/xfzl-kykhd.html ...

  6. while死循环问题-输入字符就会死循环

    问题: 是否会遇到这样的问题,在while循环中 sanf("%d",&a);如果输入的不是数字,是字符就会进入死循环. 解决方案:都是缓冲区惹的祸,输入字符后,字符会一直 ...

  7. Python 字典 Print 格式化

    __author__ = 'dell' ab = {'Swaroop': 'swaroopch@byteofpython.info', 'Larry': 'larry@wall.org', 'Mats ...

  8. 设置android状态栏颜色和toolbar颜色一致

    使用:https://github.com/jgilfelt/SystemBarTint在Activity中:@Overrideprotected void onCreate(Bundle saved ...

  9. jQuery Asynchronous

    http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html http:// ...

  10. Shuffle'm Up

    poj3087:http://poj.org/problem?id=3087 题意:题意简化之后的就是:给你两个长度均为c的字符串s1,s2,然后给你一个2*c的串ss,现在每次从s2,中取一个,然后 ...