Spring在启动Dubbo服务端应用时,会实例化ServiceBean<T>并设置配置属性,然后调用export方法:

    @SuppressWarnings({"unchecked", "deprecation"})
public void afterPropertiesSet() throws Exception {
// 设置一揽子provider属性
...... if (!isDelay()) {
export();
}
}

此后调用的是ServiceConfig中的doExportUrls方法:

    @SuppressWarnings({"unchecked", "rawtypes"})
private void doExportUrls() {
// 获取注册中心地址
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}

最终实现的是如下逻辑:

    private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
// 省略...
...... String scope = url.getParameter(Constants.SCOPE_KEY);
// don't export when none is configured
if (!Constants.SCOPE_NONE.toString().equalsIgnoreCase(scope)) { // export to local if the config is not remote (export to remote only when config is remote)
if (!Constants.SCOPE_REMOTE.toString().equalsIgnoreCase(scope)) {
// 暴露到本地,使用injvm协议,本地调用服务时会采用此协议
exportLocal(url);
}
// export to remote if the config is not local (export to local only when config is local)
if (!Constants.SCOPE_LOCAL.toString().equalsIgnoreCase(scope)) {
// 暴露到服务注册中心
if (logger.isInfoEnabled()) {
logger.info("Export dubbo service " + interfaceClass.getName() + " to url " + url);
}
if (registryURLs != null && !registryURLs.isEmpty()) {
for (URL registryURL : registryURLs) {
url = url.addParameterIfAbsent("dynamic", registryURL.getParameter("dynamic"));
URL monitorUrl = loadMonitor(registryURL);
if (monitorUrl != null) {
url = url.addParameterAndEncoded(Constants.MONITOR_KEY, monitorUrl.toFullString());
}
if (logger.isInfoEnabled()) {
logger.info("Register dubbo service " + interfaceClass.getName() + " url " + url + " to registry " + registryURL);
}
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, registryURL.addParameterAndEncoded(Constants.EXPORT_KEY, url.toFullString()));
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); // 暴露服务,protocol实例为ProtocolListenerWrapper,ProtocolListenerWrapper使用装饰器模式,会不断的调用Protocol接口的子类实例
Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
} else {
Invoker<?> invoker = proxyFactory.getInvoker(ref, (Class) interfaceClass, url);
DelegateProviderMetaDataInvoker wrapperInvoker = new DelegateProviderMetaDataInvoker(invoker, this); Exporter<?> exporter = protocol.export(wrapperInvoker);
exporters.add(exporter);
}
}
}
this.urls.add(url);
}

代码 Exporter<?> exporter = protocol.export(wrapperInvoker); protocol实例为ProtocolListenerWrapper,ProtocolListenerWrapper使用了装饰器模式,依次包装了Protocol接口的子类,其中最重要的两个子类是DubboProtocol和RegistryProtocol。DubboProtocol的主要功能是启动NettyServer和重置服务URL的部分参数,RegistryProtocol的主要功能是暴露服务到注册中心,例如zookeeper。

接下来先看DubboProtocol的export方法:

    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
URL url = invoker.getUrl(); // export service.
String key = serviceKey(url);
DubboExporter<T> exporter = new DubboExporter<T>(invoker, key, exporterMap);
exporterMap.put(key, exporter); //export an stub service for dispatching 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);
}
} // 启动NettyServer和重置服务URL的部分参数
openServer(url);
optimizeSerialization(url);
return exporter;
}
    private void openServer(URL url) {
// find server.
String key = url.getAddress();
//client can export a service which's only for server to invoke
boolean isServer = url.getParameter(Constants.IS_SERVER_KEY, true);
if (isServer) {
ExchangeServer server = serverMap.get(key);
if (server == null) {
// 启动NettyServer并放入serverMap
serverMap.put(key, createServer(url));
} else {
// server supports reset, use together with override
// 重置服务URL的部分参数
server.reset(url);
}
}
}
    private ExchangeServer createServer(URL url) {

        ......

        url = url.addParameter(Constants.CODEC_KEY, DubboCodec.NAME);
ExchangeServer server;
try {
// 启动NettyServer
server = Exchangers.bind(url, requestHandler);
} catch (RemotingException e) {
throw new RpcException("Fail to start server(url: " + url + ") " + e.getMessage(), e);
} ...... return server;
}

最终会调用HeaderExchanger的bind方法:

public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}

剩下就是实例化NettyServer了,这里不再贴出该部分代码,若感兴趣可自行跟踪源码啦。

这里注意到NettyServer中有一个属性channels,这里维护了所有客户端的连接。

Dubbo实践(十三)Export的更多相关文章

  1. Dubbo实践(六)Spring加载Bean流程

    根据上一小节对于spring扩展schema的介绍,大概可以猜到dubbo中相关的内容是如何实现的. 再来回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml ve ...

  2. Dubbo实践(五)扩展Spring Schema

    先回顾Dubbo实践(一)中定义的dubbo-provider.xml: <?xml version="1.0" encoding="UTF-8"?> ...

  3. Dubbo实践(十五)消费者引用服务

    Refer取得invoker的过程 <!-- 指定了哪种的注册中心,是基于zookeeper协议的,指定了注册中心的地址以及端口号 --> <dubbo:registry proto ...

  4. Dubbo实践(十四)生产者发布服务

    Export发布服务流程 Dubbo协议向注册中心发布服务:当服务提供方,向dubbo协议的注册中心发布服务的时候,是如何获取,创建注册中心的,如何注册以及订阅服务的,下面我们来分析其流程. 看如下配 ...

  5. Dubbo实践(八)扩展点装饰

    Filter Filter是Dubbo里面非常重要的模块,Dubbo里面日志记录.超时等功能都是在这一部分实现. 如上一节在介绍扩展点加载时所述,在生成Protocol的invoker时,实际上使用了 ...

  6. Dubbo实践(七)扩展点

    与JDK的SPI机制类似,Dubbo也在META-INF路径下定义了多种扩展接口.只是JDK SPI机制是Java后台帮你实现读取文件并对接具体的实现类,而Dubbo是自己去读文件. 扩展点配置 扩展 ...

  7. Dubbo实践(四)设计模式

    Dubbo框架在初始化和通信过程中使用了多种设计模式,可灵活控制类加载.权限控制等功能. 工厂模式 Provider在export服务时,会调用ServiceConfig的export方法.Servi ...

  8. 阿里技术专家详解 Dubbo 实践,演进及未来规划

    Dubbo 整体介绍 Dubbo 是一款高性能,轻量级的 Java RPC 框架.虽然它是以 Java 语言来出名的,但是现在我们生态里面已经有 Go.Python.PHP.Node.JS 等等语言. ...

  9. dubbo实践

    最近公司准备重构内部服务模块,准备使用dubbo,故研究一下. 官方文档:http://alibaba.github.io/dubbo-doc-static/Home-zh.htm 1. 用maven ...

随机推荐

  1. bash shell学习笔记(一)—— 常用命令

    一.基本的bash shell命令 1.默认bash shell 提示符是美元符号($); 2.bash手册 使用man命令来访问存储在Linux系统上的手册页面,如: bogon:~ Mac$ ma ...

  2. 多线程拷贝备份文件方法(Windows)

    D:\bat\robocopy.exe D:\backupdata  \\192.168.36.45\BData\  db_20170716.dmp 解释: 微软提供的robocopy.exe命令,默 ...

  3. Spring Data MongoDB 环境搭建

    一.开发环境 spring版本:4.0.6.RELEASE spring-data-mongodb版本:1.4.1.RELEASE junit版本 4.11 maven版本:3.0.5 二.pom.x ...

  4. Vue打包桌面程序

    开源的地址:https://github.com/electron/electron-quick-start 一.运行 1. 安装依赖 cnpm install electron --save cnp ...

  5. 关于modelmap.addAttribute("",)转到jsp页面获取不到值的问题

    问题一,可能是你设置的web.xml的头有问题 掉坑里好一会,发现我默认生成的web.xml中头部的配置是 <!DOCTYPE web-app PUBLIC "-//Sun Micro ...

  6. Grunt入门学习之(3) -- Gruntfile具体示例

    经过前面的学习,将测试的Gruntfile整合在一起! /** * Created by Administrator on 2017/6/22. */ module.exports = functio ...

  7. Ubuntu 16.04 Apache2 更改访问html根路径方案(可解决403)

    (1)确定html文件在服务器主机上的部署路径.例:/home/rl/vc/ (2)修改 vim sites-enabled/000-default.conf  中 DirectoryRoot 为 : ...

  8. 线性表的Java实现--链式存储(双向链表)

    有了单向链表的基础,双向链表的实现就容易多了. 双向链表的一般情况: 增加节点: 删除节点: 双向链表的Java实现: package com.liuhao.algorithm;      publi ...

  9. Selenium+java项目测试问题整理

    一.页面跳转到另一链接 问题描述:打开页面链接为A.com,但是页面元素需跳转到链接B.com.这时B页面将无法识别该元素,导致拨错 解决方案:重新自定义驱动,打开新链接 (PS:比较笨的解决方法,但 ...

  10. Python3 中日语料分句实现

    0. 背景 因为最近在看平行语料句对齐.词对齐的缘故,想做对齐的话需要先做一个分句. 一开始利用正则和引号开关标志写了一种方法,中间想到一个小技巧,写出来比较简单通用,想把这一小段代码分享一下. 1. ...