Transport网络传输层
1请求/响应的处理流程
NettyHandler:继承netty对象SimpleChannelHandler,重写了channelConnected、channelDisconnected、messageReceived、writeRequested、exceptionCaught方法,当netty的通道发生连接、断开连接、收到消息、写入消息、捕获异常等事件时触发NettyHandler中的对应方法。在这些方法中后续的处理链为:NettyServer/NettyClient—>MultiMessageHandler-->HeartbeatHandler—> AllChannelHandler —>DecodeHandler —>
HeaderExchangerHandler —> DubboProtocol$requestHandler,此链条为回调工作的处理流程。
MultiMessageHandler 对于消息的received事件,如果消息是批量传输的,解码后会由MultiMessage承载,并遍历其中的消息,交由下一个handler处理。
HeartbeatHandler:设置通道的读写时间戳
1)对于connected事件,设置通道的读写时间戳为当前时间;
2)对于disconnected事件,清空读写时间戳;
3)对于sent事件,设置通道的写时间戳为当前时间;
4)对于received事件,设置通道的读时间戳为当前时间;若消息是心跳消息请求(mEvent=true and mData=null),如果此心跳事件需要响应(mTwoWay=true),则构建心跳响应对象Response,并发送响应消息,不做后续channel处理;若消息是心跳响应(mEvent=true andmData=null),记录日志直接返回,不在做后续的channel处理;若不是心跳消息,则交由下一个处理器处理。
由Dispatcher创建的各类Handler处理器:根据URL参数dispather选择Dispatcher类,不同的Dispatcher创建不同的Handler,表示通道的事件(connected、disconnected、received、caught、sent)的处理模式。在这些Handler中构建异步执行任务ChannelEventRunnable,异步执行connected、disconnected、received、caught、sent等操作。目前支持四种Handler处理器:
1)AllChannelHandler:除发送消息之外,所有的事件都采用线程池处理;
2)ExecutionChannelHandler:除发送消息之外,其他全部使用线程池处理;与AllChannelHandler不同之处在于,若创建的线程池ExecutorService不可用,AllChannelHandler将使用共享线程池,而ExecutionChannelHandler只有报错了。
3)ChannelHandler:所有事件都直接有ChannelHandler处理,不采用线程池;
4)MessageOnlyChannelHandler:只有接受消息采用线程池;
5)ConnectionOrderedDispatcher:没搞明白;
在上述Handler的初始化过程中,会根据URL的参数threadpool来创建线程池,目前支持的线程池类型有三种,默认选择FixedThreadPool。
1)FixedThreadPool:此线程池启动时即创建固定大小的线程数,不做任何伸缩;
2)CachedThreadPool:此线程池可伸缩,线程空闲一分钟后回收,新请求重新创建线程;
3)LimitedThreadPool:此线程池一直增长,直到上限,增长后不收缩;
DecodeHandler:对读取的消息进行decode操作。
HeaderExchangeHandler:处理connected、disconnected、sent、received、caught等事件,并调用DubboProtocol$requestHandler内部类响应的事件方法。
1)connected事件:更新通道的读取时间戳和写入时间戳。调用DubboProtocol$requestHandler匿名内部类的connected事件方法。
2)disconnected事件:更新通道的读取时间戳和写入时间戳。调用DubboProtocol$requestHandler匿名内部类的disconnected事件方法(由ondisconnect属性配置)。
3)sent事件:更新通道的写入时间戳。回调DubboProtocol$requestHandler匿名内部类的sent,由于该内部类未重写sent方法,即调用父类的该方法,父类未实现任何处理逻辑。如果消息是Request,即是发送请求,则根据请求的唯一标识ID获取DefaultFuture对象,并设置发送时间为当前时间,用于在超时之后分析客户端的耗时、服务端的耗时。
4)received事件:更新通道的读取时间戳。如果是Request请求,并且需要对请求做回执时,则首先调用DubboProtocol$requestHandler匿名内部类的replay方法,在该方法中完成服务端本地方法调用并返回结果;然后根据Request对象的ID构建Response对象,将回调服务的执行结果作为Response对象的结果字段;最后调用channel.send方法向客户端发送响应消息。如果是Request请求并且不需要对请求做回执时,则调用DubboProtocol$requestHandler匿名内部类的received方法。 如果是Response且不是心跳响应,则根据response中的ID获取DefaultFuture对象,若DefaultFuture对象不存在,则该响应已经超时并且已经被删除了,若还存在,则设置response的值,唤醒线程,DefaultFuture对象的get方法返回调用值。
DubboProtocol$requestHandler:匿名内部类,实现了抽象类ExchangeHandlerAdapter类。
1)connected方法:检查URL中是否有“onconnect”参数,若有则回调该参数指定的方法;
2)disconnected方法:检查URL中是否有“ondisconnect”参数,若有则回调该参数指定的方法;
3)received方法:若消息是Invocation对象则调用reply方法,根据生成的serviceKey在AbstractProtocol.exporterMap中查找DubboExporter对象,然后根据此exporter对象获取服务端创建的invoker对象,从而完成服务端的本地方法调用;若不是则调用父类的received方法,不进行任何逻辑处理。
一、消费端发起远程调用的底层通信活动图
二、服务提供端接收请求并响应的底层通信
2 回调服务的处理逻辑
一、服务器的处理方式
以Netty为例,首先在初始化NettyClient或者NettyServer的时候,根据URL中的codec参数选择具体的codec类,默认使用DubboCountCodec类。
如下代码所示,在启动
Netty
客户端或者服务端的时候在
Netty
的
pipeline
中添加了编解码器。该编解码器就是上面根据
URL
的参数选择出来的
。
decoder为解码器,是一个SimpleChannelUpstreamHandler,从Socket到Netty中的时候,需要解码,也就是接收消息的时候,需要解码。
encoder是编码器,是OneToOneEncoder,这个类实现了ChannelDownstreamHandler,从发送消息的时候,需要编码。
nettyHandler实现了ChannelUpstreamHandler, ChannelDownstreamHandler两个,上下的时候都需要处理。
接收消息的时候,会先执行decoder,然后执行nettyHandler。
发送消息的时候,会先执行nettyHandler,然后执行encoder。
二、客户端发送调用请求的逻辑
1、先执行nettyHandler的writeRquested方法,从而decodeHandler的sent方法,该handler未实现sent方法,因而调用父类的方法透传请求。
2、执行encoder,调用链为:NettyCodecAdapter$InternalEncoder.encode --> DubboCountCodec.encode-->DubboCodec.encode-->ExchangeCodec.encode à…à DubboCodec.encodeRequestData,在该调用链中,最终调用CallbackServiceCodec.encodeInvocationArgument方法,在该方法中检查远程方法的参数是否为回调函数,若是则将客户端中调用远程方法时传入的回调函数参数暴露出来提供服务端使用,在CallbackServiceCodec.exportOrunexportCallbackService方法中完成回调函数是服务暴露,大致逻辑是:
1)生产一个唯一实例ID;
2)代理工厂创建Invoker代理;
3)调用代理工厂Protocol$Adpative根据URL中的协议选择具体的Protocol处理类,调用export方法,具体逻辑与《各类型暴露服务逻辑》一致。
三、服务端接受客户端请求的处理逻辑
1、先执行decoder,调用链如下:
NettyCodecAdapter$InternalDecoder.messageReceived –>DubboCountCodec.decode --> DubboCodec.decode--> DubboCodec.decodeBody -->DecodeableRpcInvocation.decode -->…-->CallbackServiceCodec.decodeInvocationArgument,在decodeInvocationArgument方法中判断该调用的方法中参数是否为回调函数,若是则调用CallbackServiceCodec.referOrdestroyCallbackService方法完成对客户端暴露的回调函数的服务引用。大致逻辑:
1)初始化ChannelWrappedInvoker 对象,其中将与客户端建立的通道Channel对象中参数之一,此Channel参数是回调函数消息发送的重要通道,在触发回调工作时,利用此Channel创建HeaderExchangeClient对象,由该对象完成回调的请求工作,具体逻辑与消费端发起远程调用的逻辑基本一致。
2)创建服务类的本地代理,即为ChannelWrappedInvoker 对象创建代理,将此代理作为服务端方法中回调参数的请求值,从而在服务端的方式实现中就可以使用该代理完成远程回调工作。
3)将DecodeableRpcInvocation类中的hasDecoded变量设置为true,以免在DecodeHandler中重复执行此解码工作。
=================================
以下是本人对上文的补充:
装饰者模式在transport层的应用
抽象构件(原始功能接口):ChannelHandlerDelegate
具体构件(原始功能类):HeaderExchangeHandler
装饰者:AbstractChannelHandlerDelegate、WrappedChannelHandler (是的,这里装饰者有2个)
具体装饰者(装饰者子类):DecodeHandler、MutiMessageHandler、HeartbeatHandler、AllChannelHandler
DecodeHandler的装饰逻辑是:
如果message是可以解码的,先把message解码,再让原始handler继续处理message
public class DecodeHandler extends AbstractChannelHandlerDelegate {
private static final Logger log = LoggerFactory.getLogger(DecodeHandler.class);
public DecodeHandler(ChannelHandler handler) {
super(handler);
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof Decodeable) {
decode(message);
}
if (message instanceof Request) {
decode(((Request) message).getData());
}
if (message instanceof Response) {
decode(((Response) message).getResult());
}
handler.received(channel, message);
}
.......................
}
MutimessageHandler的装饰逻辑是:
如果(解码后的)message是批量消息,遍历每条消息,交由原始handler处理。
public class MultiMessageHandler extends AbstractChannelHandlerDelegate {
public MultiMessageHandler(ChannelHandler handler) {
super(handler);
}
@SuppressWarnings("unchecked")
@Override
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof MultiMessage) {
MultiMessage list = (MultiMessage) message;
for (Object obj : list) {
handler.received(channel, obj);
}
} else {
handler.received(channel, message);
}
}
}
HeartBeatHandler的装饰逻辑是:
设置通道的读写时间戳,再交由原始handler处理
public class HeartbeatHandler extends AbstractChannelHandlerDelegate {
.................
public HeartbeatHandler(ChannelHandler handler) {
super(handler);
}
@Override
public void connected(Channel channel) throws RemotingException {
setReadTimestamp(channel); //对于connected事件,设置通道的读写时间戳为当前时间,再交由下个handler处理;
setWriteTimestamp(channel);
handler.connected(channel);
}
@Override
public void disconnected(Channel channel) throws RemotingException {
clearReadTimestamp(channel); //对于disconnected事件,清空读写时间戳;
clearWriteTimestamp(channel);
handler.disconnected(channel);
}
@Override
public void sent(Channel channel, Object message) throws RemotingException {
setWriteTimestamp(channel);
handler.sent(channel, message);
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
setReadTimestamp(channel);
if (isHeartbeatRequest(message)) {
Request req = (Request) message;
if (req.isTwoWay()) {
Response res = new Response(req.getId(), req.getVersion());
res.setEvent(Response.HEARTBEAT_EVENT);
channel.send(res);
if (logger.isInfoEnabled()) {
int heartbeat = channel.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);
if (logger.isDebugEnabled()) {
logger.debug("Received heartbeat from remote channel " + channel.getRemoteAddress()
+ ", cause: The channel has no data-transmission exceeds a heartbeat period"
+ (heartbeat > 0 ? ": " + heartbeat + "ms" : ""));
}
}
}
return;
}
if (isHeartbeatResponse(message)) {
if (logger.isDebugEnabled()) {
logger.debug("Receive heartbeat response in thread " + Thread.currentThread().getName());
}
return;
}
handler.received(channel, message);
}
在HeaderExchanger中,我们可以看到DecodeHandler对HeaderExchangeHandler产生装饰关系
public class HeaderExchanger implements Exchanger {
public static final String NAME = "header";
@Override
public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
}
@Override
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
}
AllChannelHandler也是具体装饰者,但与上面的具体装饰者不同,它是WrappedChannelHandler装饰者的子类。
它用于将handler放入一个线程池中处理。线程池在父类中定义,在本类中调用。
public class AllChannelHandler extends WrappedChannelHandler {
public AllChannelHandler(ChannelHandler handler, URL url) {
super(handler, url);
}
@Override
public void connected(Channel channel) throws RemotingException {
ExecutorService cexecutor = getExecutorService();
try {
cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CONNECTED));
} catch (Throwable t) {
throw new ExecutionException("connect event", channel, getClass() + " error when process connected event .", t);
}
}
@Override
public void disconnected(Channel channel) throws RemotingException {
ExecutorService cexecutor = getExecutorService();
try {
cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.DISCONNECTED));
} catch (Throwable t) {
throw new ExecutionException("disconnect event", channel, getClass() + " error when process disconnected event .", t);
}
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
ExecutorService cexecutor = getExecutorService();
try {
cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));
} catch (Throwable t) {
//TODO A temporary solution to the problem that the exception information can not be sent to the opposite end after the thread pool is full. Need a refactoring
//fix The thread pool is full, refuses to call, does not return, and causes the consumer to wait for time out
if(message instanceof Request && t instanceof RejectedExecutionException){
Request request = (Request)message;
if(request.isTwoWay()){
String msg = "Server side(" + url.getIp() + "," + url.getPort() + ") threadpool is exhausted ,detail msg:" + t.getMessage();
Response response = new Response(request.getId(), request.getVersion());
response.setStatus(Response.SERVER_THREADPOOL_EXHAUSTED_ERROR);
response.setErrorMessage(msg);
channel.send(response);
return;
}
}
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
@Override
public void caught(Channel channel, Throwable exception) throws RemotingException {
ExecutorService cexecutor = getExecutorService();
try {
cexecutor.execute(new ChannelEventRunnable(channel, handler, ChannelState.CAUGHT, exception));
} catch (Throwable t) {
throw new ExecutionException("caught event", channel, getClass() + " error when process caught event .", t);
}
}
}
在AllDispatcher中调用AllChannelHandler
public class AllDispatcher implements Dispatcher {
public static final String NAME = "all";
@Override
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
return new AllChannelHandler(handler, url);
}
}
在ChannelHandlers中我们可以看到MutiMessageHandler、HeartBeatHandler、AllChannelHandler的装饰关系
public class ChannelHandlers {
...............................
protected ChannelHandler wrapInternal(ChannelHandler handler, URL url) {
return new MultiMessageHandler(new HeartbeatHandler(ExtensionLoader.getExtensionLoader(Dispatcher.class)
.getAdaptiveExtension().dispatch(handler, url)));
}
}
前面讲了那么多具体装饰者,下面让我们把目光放回到原始功能类HeaderExhangeHandler。
HeaderExchangerHandler是信息交换Handler,将请求转化成请求响应模式与同步转异步模式。
RequestHandler是最后执行的Handler,会在协议层选择Exporter后选择Invoker,进而执行Filter与Invoker,最终执行请求服务实现类方法。
下面让我们来看一下HeaderExchangeHandler是怎么实现请求转化成请求响应模式和同步转异步模式的?
主要是靠判断同步调用还是异步调用,一般默认同步,同步则走handleRequest()方法。
HeaderExchangeHandler:处理connected、disconnected、sent、received、caught等事件,并调用DubboProtocol$requestHandler内部类响应的事件方法。
1)connected事件:更新通道的读取时间戳和写入时间戳。调用DubboProtocol$requestHandler匿名内部类的connected事件方法。
2)disconnected事件:更新通道的读取时间戳和写入时间戳。调用DubboProtocol$requestHandler匿名内部类的disconnected事件方法(由ondisconnect属性配置)。
3)sent事件:更新通道的写入时间戳。回调DubboProtocol$requestHandler匿名内部类的sent,由于该内部类未重写sent方法,即调用父类的该方法,父类未实现任何处理逻辑。如果消息是Request,即是发送请求,则根据请求的唯一标识ID获取DefaultFuture对象,并设置发送时间为当前时间,用于在超时之后分析客户端的耗时、服务端的耗时。
4)received事件:更新通道的读取时间戳。如果是Request请求,并且需要对请求做回执时,则首先调用DubboProtocol$requestHandler匿名内部类的reply方法,在该方法中完成服务端本地方法调用并返回结果;然后根据Request对象的ID构建Response对象,将回调服务的执行结果作为Response对象的结果字段;最后调用channel.send方法向客户端发送响应消息。如果是Request请求并且不需要对请求做回执时,则调用DubboProtocol$requestHandler匿名内部类的received方法。 如果是Response且不是心跳响应,则根据response中的ID获取DefaultFuture对象,若DefaultFuture对象不存在,则该响应已经超时并且已经被删除了,若还存在,则设置response的值,唤醒线程,DefaultFuture对象的get方法返回调用值。
DubboProtocol$requestHandler:匿名内部类,实现了抽象类ExchangeHandlerAdapter类。
1)connected方法:检查URL中是否有“onconnect”参数,若有则回调该参数指定的方法;
2)disconnected方法:检查URL中是否有“ondisconnect”参数,若有则回调该参数指定的方法;
3)received方法:若消息是Invocation对象则调用reply方法,根据生成的serviceKey在AbstractProtocol.exporterMap中查找DubboExporter对象,然后根据此exporter对象获取服务端创建的invoker对象,从而完成服务端的本地方法调用;若不是则调用父类的received方法,不进行任何逻辑处理。
HeaderExchangeHandler代码如下:
在HeaderExchangeHandler类中主要关注received方法,普通的同步接口twoWay属性是true走handleRequest方法处理请求,处理结束之后调用channel.send把结果返回到客户端。
handleRequest()方法再走下一个handler的reply,这个handler就是DubboProtocol.requestHandler,把request对象中的data取出来传到requestHandler中
public class HeaderExchangeHandler implements ChannelHandlerDelegate {
protected static final Logger logger = LoggerFactory.getLogger(HeaderExchangeHandler.class);
public static String KEY_READ_TIMESTAMP = HeartbeatHandler.KEY_READ_TIMESTAMP;
public static String KEY_WRITE_TIMESTAMP = HeartbeatHandler.KEY_WRITE_TIMESTAMP;
private final ExchangeHandler handler;
public HeaderExchangeHandler(ExchangeHandler handler) {
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
this.handler = handler;
}
static void handleResponse(Channel channel, Response response) throws RemotingException {
if (response != null && !response.isHeartbeat()) {
DefaultFuture.received(channel, response);
}
}
private static boolean isClientSide(Channel channel) {
InetSocketAddress address = channel.getRemoteAddress();
URL url = channel.getUrl();
return url.getPort() == address.getPort() &&
NetUtils.filterLocalHost(url.getIp())
.equals(NetUtils.filterLocalHost(address.getAddress().getHostAddress()));
}
void handlerEvent(Channel channel, Request req) throws RemotingException {
if (req.getData() != null && req.getData().equals(Request.READONLY_EVENT)) {
channel.setAttribute(Constants.CHANNEL_ATTRIBUTE_READONLY_KEY, Boolean.TRUE);
}
}
Response handleRequest(ExchangeChannel channel, Request req) throws RemotingException {
Response res = new Response(req.getId(), req.getVersion());
if (req.isBroken()) {
Object data = req.getData();
String msg;
if (data == null) msg = null;
else if (data instanceof Throwable) msg = StringUtils.toString((Throwable) data);
else msg = data.toString();
res.setErrorMessage("Fail to decode request due to: " + msg);
res.setStatus(Response.BAD_REQUEST);
return res;
}
// find handler by message class.
Object msg = req.getData(); //把request对象中的data取出来传到requestHandler中
try {
// handle data.
Object result = handler.reply(channel, msg);//这个handler就是DubboProtocol.requestHandler,调用它的reply()方法
res.setStatus(Response.OK);
res.setResult(result);
} catch (Throwable e) {
res.setStatus(Response.SERVICE_ERROR);
res.setErrorMessage(StringUtils.toString(e));
}
return res;
}
@Override
public void connected(Channel channel) throws RemotingException {
channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis());
ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
try {
handler.connected(exchangeChannel);
} finally {
HeaderExchangeChannel.removeChannelIfDisconnected(channel);
}
}
@Override
public void disconnected(Channel channel) throws RemotingException {
channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis());
ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
try {
handler.disconnected(exchangeChannel);
} finally {
HeaderExchangeChannel.removeChannelIfDisconnected(channel);
}
}
@Override
public void sent(Channel channel, Object message) throws RemotingException {
Throwable exception = null;
try {
channel.setAttribute(KEY_WRITE_TIMESTAMP, System.currentTimeMillis());
ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
try {
handler.sent(exchangeChannel, message);
} finally {
HeaderExchangeChannel.removeChannelIfDisconnected(channel);
}
} catch (Throwable t) {
exception = t;
}
if (message instanceof Request) {
Request request = (Request) message;
DefaultFuture.sent(channel, request);
}
if (exception != null) {
if (exception instanceof RuntimeException) {
throw (RuntimeException) exception;
} else if (exception instanceof RemotingException) {
throw (RemotingException) exception;
} else {
throw new RemotingException(channel.getLocalAddress(), channel.getRemoteAddress(),
exception.getMessage(), exception);
}
}
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
channel.setAttribute(KEY_READ_TIMESTAMP, System.currentTimeMillis());
ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
try {
if (message instanceof Request) {
// handle request.
Request request = (Request) message;
if (request.isEvent()) {
handlerEvent(channel, request);
} else {
if (request.isTwoWay()) { //同步走handleRequest()方法
Response response = handleRequest(exchangeChannel, request);
channel.send(response);
} else {
handler.received(exchangeChannel, request.getData());
}
}
} else if (message instanceof Response) {
handleResponse(channel, (Response) message);
} else if (message instanceof String) {
if (isClientSide(channel)) {
Exception e = new Exception("Dubbo client can not supported string message: " + message + " in channel: " + channel + ", url: " + channel.getUrl());
logger.error(e.getMessage(), e);
} else {
String echo = handler.telnet(channel, (String) message);
if (echo != null && echo.length() > 0) {
channel.send(echo);
}
}
} else {
handler.received(exchangeChannel, message);
}
} finally {
HeaderExchangeChannel.removeChannelIfDisconnected(channel);
}
}
@Override
public void caught(Channel channel, Throwable exception) throws RemotingException {
if (exception instanceof ExecutionException) {
ExecutionException e = (ExecutionException) exception;
Object msg = e.getRequest();
if (msg instanceof Request) {
Request req = (Request) msg;
if (req.isTwoWay() && !req.isHeartbeat()) {
Response res = new Response(req.getId(), req.getVersion());
res.setStatus(Response.SERVER_ERROR);
res.setErrorMessage(StringUtils.toString(e));
channel.send(res);
return;
}
}
}
ExchangeChannel exchangeChannel = HeaderExchangeChannel.getOrAddChannel(channel);
try {
handler.caught(exchangeChannel, exception);
} finally {
HeaderExchangeChannel.removeChannelIfDisconnected(channel);
}
}
@Override
public ChannelHandler getHandler() {
if (handler instanceof ChannelHandlerDelegate) {
return ((ChannelHandlerDelegate) handler).getHandler();
} else {
return handler;
}
}
}
requestHandler代码如下:
requestHandler的reply()方法查找提供端请求对应的Invoker,在接口提供者初始化时,每个接口都会创建一个Invoker和Exporter,Exporter持有invoker实例,Exporter对象保存在DubboProtocol的exporterMap中,key是由URL生成的serviceKey,此时通过Invocation中的信息就可还原该serviceKey并且找到对应的Exporter和Invoker,在分析提供者初始化代码时知道它是Invoker-Filter的头节点,激活Filter后调用由ProxyFactory生成的Invoker:
private ExchangeHandler requestHandler = new ExchangeHandlerAdapter() {
@Override
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
Invoker<?> invoker = getInvoker(channel, inv);
// need to consider backward-compatibility if it's a 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());
}
@Override
public void received(Channel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
reply((ExchangeChannel) channel, message);
} else {
super.received(channel, message);
}
}
@Override
public void connected(Channel channel) throws RemotingException {
invoke(channel, Constants.ON_CONNECT_KEY);
}
@Override
public void disconnected(Channel channel) throws RemotingException {
if (logger.isInfoEnabled()) {
logger.info("disconnected from " + channel.getRemoteAddress() + ",url:" + channel.getUrl());
}
invoke(channel, Constants.ON_DISCONNECT_KEY);
}
private void invoke(Channel channel, String methodKey) {
Invocation invocation = createInvocation(channel, channel.getUrl(), methodKey);
if (invocation != null) {
try {
received(channel, invocation);
} catch (Throwable t) {
logger.warn("Failed to invoke event method " + invocation.getMethodName() + "(), cause: " + t.getMessage(), t);
}
}
}
private Invocation createInvocation(Channel channel, URL url, String methodKey) {
String method = url.getParameter(methodKey);
if (method == null || method.length() == 0) {
return null;
}
RpcInvocation invocation = new RpcInvocation(method, new Class<?>[0], new Object[0]);
invocation.setAttachment(Constants.PATH_KEY, url.getPath());
invocation.setAttachment(Constants.GROUP_KEY, url.getParameter(Constants.GROUP_KEY));
invocation.setAttachment(Constants.INTERFACE_KEY, url.getParameter(Constants.INTERFACE_KEY));
invocation.setAttachment(Constants.VERSION_KEY, url.getParameter(Constants.VERSION_KEY));
if (url.getParameter(Constants.STUB_EVENT_KEY, false)) {
invocation.setAttachment(Constants.STUB_EVENT_KEY, Boolean.TRUE.toString());
}
return invocation;
}
};
装饰者模式在transport层的应用到此结束
============================
transport层只有以上装饰者模式中讲到的MultiMessageHandler、HeartBeatHandler、AllChannelHandler、DecodeChannelHandler、HeaderExchangeHandler、DubboProtocol$requestHandler吗?
ps:事实上,HeartBeatHandler、HeaderExchangeHandler是在exchange包路径下的。
事实上,transport层的核心不是这些,而是NettyClient、NettyServer、NettyCodecAdapter、NettyHandler。
在netty4包中,NettyHandler已经变成了NettyClientHandler和NettyServerHandler。
下面以netty4包为例
NettyServer中定义了netty的引导服务器:
public class NettyServer extends AbstractServer implements Server {
private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);
private Map<String, Channel> channels; // <ip:port, channel>
private ServerBootstrap bootstrap;
private io.netty.channel.Channel channel;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
public NettyServer(URL url, ChannelHandler handler) throws RemotingException {
super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}
@Override
protected void doOpen() throws Throwable {
bootstrap = new ServerBootstrap();
bossGroup = new NioEventLoopGroup(1, new DefaultThreadFactory("NettyServerBoss", true));
workerGroup = new NioEventLoopGroup(getUrl().getPositiveParameter(Constants.IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),
new DefaultThreadFactory("NettyServerWorker", true));
final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);
channels = nettyServerHandler.getChannels();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE)
.childOption(ChannelOption.SO_REUSEADDR, Boolean.TRUE)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) throws Exception {
NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);
ch.pipeline()//.addLast("logging",new LoggingHandler(LogLevel.INFO))//for debug
.addLast("decoder", adapter.getDecoder())
.addLast("encoder", adapter.getEncoder())
.addLast("handler", nettyServerHandler);
}
});
// bind
ChannelFuture channelFuture = bootstrap.bind(getBindAddress());
channelFuture.syncUninterruptibly();
channel = channelFuture.channel();
}
@Override
protected void doClose() throws Throwable {
try {
if (channel != null) {
// unbind.
channel.close();
}
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
try {
Collection<com.alibaba.dubbo.remoting.Channel> channels = getChannels();
if (channels != null && channels.size() > 0) {
for (com.alibaba.dubbo.remoting.Channel channel : channels) {
try {
channel.close();
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
}
}
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
try {
if (bootstrap != null) {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
try {
if (channels != null) {
channels.clear();
}
} catch (Throwable e) {
logger.warn(e.getMessage(), e);
}
}
@Override
public Collection<Channel> getChannels() {
Collection<Channel> chs = new HashSet<Channel>();
for (Channel channel : this.channels.values()) {
if (channel.isConnected()) {
chs.add(channel);
} else {
channels.remove(NetUtils.toAddressString(channel.getRemoteAddress()));
}
}
return chs;
}
@Override
public Channel getChannel(InetSocketAddress remoteAddress) {
return channels.get(NetUtils.toAddressString(remoteAddress));
}
@Override
public boolean isBound() {
return channel.isActive();
}
}
从上面代码可以看出,netty的ChannelHandler处理器链为:NettyCodecAdapter.decoder->NettyCodecAdapter.encoder->NettyServerHandler
然后NettyServerHandler将对应的channel事件转发给MultiMessageHandler、HeartBeatHandler、AllChannelHandler、DecodeChannelHandler、HeaderExchangeHandler、DubboProtocol$requestHandler
NettyServerHandler继承了ChannelDuplexHandler,所以它既是入站处理器,又是出站处理器
/**
* NettyClientHandler
*/
@io.netty.channel.ChannelHandler.Sharable
public class NettyServerHandler extends ChannelDuplexHandler {
private final Map<String, Channel> channels = new ConcurrentHashMap<String, Channel>(); // <ip:port, channel>
private final URL url;
private final ChannelHandler handler;
public NettyServerHandler(URL url, ChannelHandler handler) {
if (url == null) {
throw new IllegalArgumentException("url == null");
}
if (handler == null) {
throw new IllegalArgumentException("handler == null");
}
this.url = url;
this.handler = handler;
}
public Map<String, Channel> getChannels() {
return channels;
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
try {
if (channel != null) {
channels.put(NetUtils.toAddressString((InetSocketAddress) ctx.channel().remoteAddress()), channel);
}
handler.connected(channel);
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.channel());
}
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
try {
channels.remove(NetUtils.toAddressString((InetSocketAddress) ctx.channel().remoteAddress()));
handler.disconnected(channel);
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.channel());
}
}
@Override
public void disconnect(ChannelHandlerContext ctx, ChannelPromise future)
throws Exception {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
try {
handler.received(channel, msg);
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.channel());
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
super.write(ctx, msg, promise);
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
try {
handler.sent(channel, msg);
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.channel());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
try {
handler.caught(channel, cause);
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.channel());
}
}
}