本文将深入分析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. [转]mysql导出导入中文表解决方法

    在开发过程中会经常用到mysql导出导入中文表,本文将详细介绍其如何使用,需要的朋友可以参考下. 在开发过程中会经常用到mysql导出导入中文表,本文将详细介绍其如何使用,需要的朋友可以参考下一.先针 ...

  2. C++跨平台事件机制实现

    今天看到有人在讨论C++标准没有提供类似操作系统层次的事件通知机制,如windows的事件内核对象.其实我想说的事,C++11标准里的互斥量及条件变量已经够帮我们实现类似的功能了. 刚编写了一个事件通 ...

  3. 头一回发博客,来分享个有关C++类型萃取的编写技巧

    废话不多说,上来贴代码最实在,哈哈! 以下代码量有点多,不过这都是在下一手一手敲出来的,小巧好用,把以下代码复制出来,放到相应的hpp文件即可,VS,GCC下均能编译通过 #include<io ...

  4. 再看IOC, 读深入理解DIP、IoC、DI以及IoC容器

    IoC则是一种 软件设计模式,它告诉你应该如何做,来解除相互依赖模块的耦合.控制反转(IoC),它为相互依赖的组件提供抽象,将依赖(低层模块)对象的获得交给第三方(系统)来控制,即依赖对象不在被依赖模 ...

  5. Android的进程和线程(转)

    进程和线程 当一个应用程序第一次启动的时候,Android会启动一个Linux进程和一个主线程(即UI线程:主要负责处理用户的按键事件.触屏事件及屏幕绘图事件等).默认情况下,所有该程序的组件都将在该 ...

  6. jQuery--效果和遍历

    七.jQuery效果 (1)jQuery隐藏和显示 //隐藏 $("#hide").click(function(){ $("p").hide(1000); } ...

  7. js时间戳转为日期格式

    转自:http://wyoojune.blog.163.com/blog/static/57093325201131193650725/ 这个在php+mssql(日期类型为datetime)+aja ...

  8. Windows Open with Sublime Text

    Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\*\shell\Open with Sublime Text] "Icon&q ...

  9. Plan-9效应:为什么东西不坏就不要去修它

    http://www.aqee.net/the-plan-9-effect-or-why-you-should-not-fix-it-if-it-aint-broken/ Plan-9是一个很棒的.很 ...

  10. JSP 登录页面

    1. index.jsp来提交请求 2. login.jsp来检查数据库数据 3. 需要注意的是,下载下来的mysql.conection jar包需要放到WEB-INF下面的lib文件夹下 jsp ...