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. DevExpress13.2.9 控件使用经验总结

    一.换肤功能 1. 添加 DevExpress.OfficeSkins 和 DevExpress.BonusSkins 两个引用 2. 皮肤注册 DevExpress.UserSkins.BonusS ...

  2. IIS6.0+PHP5.3+mssql 配置及远程连接数据库

    安装软件需求:IIS6.0.php5.3 .sqlsrv驱动.sql server ODBC驱动  所有软件压缩包下载 注意看:安装软件的环境需求,根据环境自行选择版本,例如odbc驱动老一点版本才能 ...

  3. DOM基础操作实战代码

    对于已经讲解给大家的DOM实战,我今天给大家几个实战代码,可以让大家加深对此的理解! 1.用DOM动态生成这样一个结构: <div class=”example”> <p class ...

  4. 使用css实现三角符号

    关于使用css制作三角符号,网上有很多的例子了,在这里只是为了详细的向各位解释一下三角符号的原理 下图,是一个长宽为100px,边框宽度为100px的一个元素,由此可见,在css中上下左右的边框相交处 ...

  5. 鼠标事件-拖拽2(不能拖出指定对象的div)

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  6. 微信小程序-view组件

    <view class="section"> <view class="section__title">flex-direction: ...

  7. Client tried to access password protected page without proper authorization (status code 401) 无法发布SceneService的解决方法

    前不久,一客户反映原来已经部署好的WebGIS系统忽然无法正常运行了,具体配置如下: Portal for ArcGIS 10.5 ArcGIS Server 10.5 Web Adpator 10. ...

  8. MySQL数据库(11)----使用子查询实现多表查询

    子查询指的是用括号括起来,并嵌入另一条语句里的那条 SELECT 语句.下面有一个示例,它实现的是找出与考试类别('T')相对应的所有考试事件行的 ID,然后利用它们来查找那些考试的成绩: SELEC ...

  9. 【html/css】模态框的实现

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  10. LinkedList源码疑问记录

    早上看linkedList源码时候,对于它的初始化一直不太明白.如下: transient int size = 0; /** * Pointer to first node. * Invariant ...