dubbo源码解析(三): Socket Server和方法调用
来源:互联网 发布:域名转让流程 编辑:程序博客网 时间:2024/06/05 10:01
之前的两篇文章给大家介绍了dubbo的扩展点加载机制以及服务启动的过程
dubbo源码解析(一): 扩展点加载(ExtensionLoader)
dubbo源码解析(二): dubbo服务的启动
本文给大家梳理一下dubbo的socket服务的启动以及一条消息过来后,dubbo框架究竟是怎么处理的。
前文提到,provider服务的暴露最后调用了protocol的export方法
Exporter<?> exporter = protocol.export(invoker);
这里配置的protocol的类型是dubbo,具体也就是DubboProtocol这个类,我们来看下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 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); } } //创建socket server openServer(url); return exporter;}
url就是上文中提到的provider的一串唯一标识符,包括了服务的ip、端口、别名以及暴露的方法等等。之后对StubSupportEvent和Callbackservice进行一些特殊化处理,这里不做深究,最后就进入到了openServer()方法。
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); } }}
getAddress()返回host:port形式的地址,作为server map的key。之后判断服务类型,如果是一个server的话,调用createServer()产生一个新的ExchangeServer,并绑定一个ExchangeHandler
ExchangeServer server;server = Exchangers.bind(url, requestHandler);
其具体类型为HeaderExchangeServer
new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
调用
getTransporter().bind(url, handler);
这里会涉及到本人dubbo系列第一篇博文的知识点,扩展点加载
public static Transporter getTransporter() { return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension(); }
加载的是Transporter的自适应扩展点,这里的自适应扩展点返回的是NettyTransporter,之后就是一个正常的netty server了。这里采用的是异步方式,传入的handler是ExchangeHandlerAdapter,当有消息到来时,进入received()方法后调用reply()方式进行回包。
public Object reply(ExchangeChannel channel, Object message) throws RemotingException { if (message instanceof Invocation) { Invocation inv = (Invocation) message; Invoker<?> invoker = getInvoker(channel, inv); //如果是callback 需要处理高版本调用低版本的问题 if (Boolean.TRUE.toString().equals(inv.getAttachments().get(IS_CALLBACK_SERVICE_INVOKE))){ String methodsStr = invoker.getUrl().getParameters().get("methods"); boolean hasMethod = false; if (methodsStr == null || methodsStr.indexOf(",") == -1){ hasMethod = inv.getMethodName().equals(methodsStr); } else { String[] methods = methodsStr.split(","); for (String method : methods){ if (inv.getMethodName().equals(method)){ hasMethod = true; break; } } } if (!hasMethod){ logger.warn(new IllegalStateException("The methodName "+inv.getMethodName()+" not found in callback service interface ,invoke will be ignored. please update the api interface. url is:" + invoker.getUrl()) +" ,invocation is :"+inv ); return null; } } RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress()); return invoker.invoke(inv); } throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());}
这里涉及到一个Invocation的概念,以下文字摘自dubbo官网:
在Dubbo的核心领域模型中:
Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。
Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
Invocation是会话域,它持有调用过程中的变量,比如方法名,参数等。
Protocol和Invoker的概念我们在上文已经提及过,这里的Invocation封装了rpc调用的MethodName、ParameterTypes、Arguments等参数。这里涉及到的实体类是RpcInvocation,RpcInvocation实现了Serializable,可序列化后进行传输。
我们回到reply()方法,在得到Invocation的实例后,查找对应的Invoker调用invoker.invoke()方法进行回包。
这里有一个获取invoker的过程,在本文最上面的export()函数中,有一步
exporterMap.put(key, exporter);
的操作,这里存储了key所对应的exporter,在reply()方法中,通过getInvoker()获取invoker,具体流程就是构造相应的key之后,从exporterMap获取对应的exporter,再找到所对应的invoker
String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY));DubboExporter<?> exporter = (DubboExporter<?>) exporterMap.get(serviceKey);if (exporter == null) throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv);return exporter.getInvoker();
到了这一步,就可以通过反射去调用server端的具体方法去回包啦。具体的invoker生成流程可以参见上文。
到这里,整个dubbo服务的启动和运行已经介绍完了,以后有空的话可能会再分析一下dubbo的负载均衡机制以及服务发现机制。
- dubbo源码解析(三): Socket Server和方法调用
- StringBuffer和StringBuilder源码解析(三)-- indexOf()方法
- dubbo源码解析
- dubbo源码解析-LoadBalance
- Skynet 源码学习 -- Socket Server 和 Skynet_socket
- dubbo框架源码核心技术解析
- dubbo rpc 调用过程解析
- dubbo源码 学习笔记(三)
- Dubbo学习(三)服务调用
- onAttachedToWindow和onDetachedFromWindow调用时机源码解析
- 王学岗ListView和源码解析(三)
- Dubbo异步方法调用里有个坑
- dubbo相关知识(三)--socket长连接和短连接
- Dubbo源码解析-Dubbo微内核实现(SPI扩展)
- dubbo源码解析(二): dubbo服务的启动
- dubbo源码阅读笔记--服务调用时序
- Dubbo源码阅读之 客户端远程调用
- client和server相互调用的方法
- Java中 printf、print、println的区别
- java多线程详解
- Android VR入门文章
- 【代码笔记】iOS-字体从右向左滚动
- 单向散列函数SHA-1算法分析与实现
- dubbo源码解析(三): Socket Server和方法调用
- PHP 伪静态规则写法RewriteRule-htaccess详细语法使用
- hadoop MapReduce 输出结果中文乱码解决
- 【loj】#6004. 「网络流 24 题」圆桌聚餐(二分图匹配)
- JAVASE jar文件的打开---Win7
- 求质数算法之试除法
- 从小菜鸟到老菜鸟
- android 6.0 7.0 不一样的处理权限适配
- Java+Selenium3框架设计准备篇10-用非PageFactory实现POM