阅读需要技能:
1.设计模式:理解代理模式。JDK动态代理类的使用。
2.设计模式:理解装饰模式。
3.Netty网络通讯编程,server,handler,channel
4.了解Dubbo基本原理,Dubbo模块各层分包关系
Dubbo RPC 服务端提供服务实现细节
服务端提供服务过程主要分为两部分:
暴露服务Exporter(用于向注册中心注册和包装好提供服务的类) 和监听服务(用于打开socket侦听服务,并接收客户端发来的各种请求)
DubboProtocol类被用于服务端和消费端,其分别对应方法export 和refer,是RPC层和REMOTING层的桥梁
下图是暴露服务的执行时序,注意此图不是服务监听执行结果并返回给客户端过程
由上图知道两大重要过程,
1是打开socket通讯提供监听客户端请求
2是把暴露的服务注册到注册中心
DubboProtocol如何为服务端打开socket通讯侦听?
细节在DubboProtocol的openserver方法
private ExchangeServer createServer(URL url) {
....
private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
...
...}
}
ExchangeServer server;
server = Exchangers.bind(url, requestHandler);
....
return server;
}
注意requestHandler,这是服务端侦听到请求后由NettyHandler调用的方法
ExchangeHandler requestHandler的使用,服务端侦听到请求后如何回调该方法?
下面补充详细调用过程。注意,在这个过程中,某些功能类在不断在初始化构建,并且有些有装饰模式不断增强功能,这些构建好的包装类,最终在监听接收客户端请求后触发。
DubboProtocol.export(Invoker) line: 253
DubboProtocol.openServer(URL) line: 266
DubboProtocol.createServer(URL) line: 287
Exchangers.bind(URL, ExchangeHandler) line: 63
HeaderExchanger.bind(URL, ExchangeHandler) line: 41
装饰模式例子1:
new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
可见,核心处理类在HeaderExchangeHandler,DecodeHandler是对其包装。Transporters后来被ExtensionLoader默认加载为NettyTransporter,其也包含HeaderExchangeHandler,同理HeaderExchangeServer也包含HeaderExchangeHandler。
继续运行调试例子,跳转到下面代码。
装饰模式例子2:
new MultiMessageHandler(new HeartbeatHandler(ExtensionLoader.getExtensionLoader(Dispatcher.class)
.getAdaptiveExtension().dispatch(handler, url)));
注意,ExtensionLoader.getExtensionLoader(Dispatcher.class)
.getAdaptiveExtension().dispatch(handler, url)) 生成AllChannelHandler
继续运行调试例子,跳转到下面代码。
可见HeaderExchangeHandler(实现ChannelHandler)被传递到NettyServer。
并且NettyServer的doOpen方法内容大部分就是Netty框架的基本应用代码,
protected void doOpen() throws Throwable {
...
ExecutorService boss = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerBoss", true));
ExecutorService worker = Executors.newCachedThreadPool(new NamedThreadFactory("NettyServerWorker", true));
final NettyHandler nettyHandler = new NettyHandler(getUrl(), this); //this包含requestHandler
...
}
回调函数requestHandler被绑定在了Netty框架的监听端,一旦有客户端请求就自动触发,这是Netty框架实现的。
至此,可以看到RPC层如何调用Remoting通讯模块了。本文通讯模块的例子取dubbo默认的Netty网络通讯框架。
DubboProtocol侦听到客户端请求时候究竟执行了什么?
RPC通讯原理就是客户端把请求执行的服务名字,调用方法名,以及方法参数通过socket发送到服务端。服务端利用服务名字反射得到对应的服务类,并且调用服务类的方法,该方法由客户端传送过来指定的方法名,参数内容也是客户端传送过来的参数值。
这个触发执行过程如下:
当有客户端请求时候,
首先DecodeHandler.received进行解码
然后HeaderExchangeHandler.handleRequest一直到NettyHandler的reply方法被触发执行(NettyHandler包装了requestHandler的reply方法),
最后执行完结果后通过channel.send发送结果回客户端。
如图:
reply方法被执行:
channel.send发送结果回客户端
- requestHandler的使用,这是服务端侦听到请求后调用的方法(业务处理)
private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
Invoker<?> invoker = getInvoker(channel, inv);
...
...
return invoker.invoke(inv);
}
}
}
注意,这里的invoker是代理类代理了真正的服务impl类
- 然后在代理类JdkProxyFactory或者JavassistProxyFactory的doInvoke(…)方法中执行,因为代理类生成invoker
Dubbo的invoker.invoke(inv); –> AbstractProxyInvoker的doInvoke(proxy, invocation.getMethodName(), invocation.getParameterTypes(), invocation.getArguments()) –> JdkProxyFactory的doInvoke(…)
总结:
DubboProtocol 利用Netty打开服务端监听操作,绑定Handler,定义Handler业务逻辑
==>
…(省略)
==>
服务端接收用户请求
HeaderExchangeHandler.received
==>
服务端处理用户请求
HeaderExchangeHandler.handleRequest
==>
服务端发送回复到用户
HeaderExchangeChannel.send(response);
==>
使用Netty框架发送
NettyChannel.send
==>
发送端Netty调用:
ChannelFuture future = channel.write(message); //org.jboss.netty.channel.Channel channel;
延伸思考
基于上面详细的代码调用链指示,相信大家对服务端和消费端如何通过通讯模块交互信息有基本认识。下面问题留给大家思考:
- DubboProtocol侦听到客户端请求执行完结果后向客户端发送了什么?
- DubboProtocol客户端如何发送请求?
- DubboProtocol客户端如何等待服务端应答?