Dubbo原始碼解析之服務端接收訊息
準備
dubbo
版本:2.5.4
服務端接收訊息流程
Handler鏈路
DubboProtocol
private ExchangeServer createServer(URL url) {
url = url.addParameterIfAbsent("channel.readonly.sent", Boolean.TRUE.toString());
url = url.addParameterIfAbsent("heartbeat", String.valueOf(60000));
String str = url.getParameter("server", "netty");
if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
throw new RpcException("Unsupported server type: " + str + ", url: " + url);
} else {
url = url.addParameter("codec", Version.isCompatibleVersion() ? "dubbo1compatible" : "dubbo");
ExchangeServer server;
try {
// requestHandler -> new ExchangeHandlerAdapter() {}
server = Exchangers.bind(url, this.requestHandler);
} catch (RemotingException var5) {
throw new RpcException("Fail to start server(url: " + url + ") " + var5.getMessage(), var5);
}
str = url.getParameter("client");
if (str != null && str.length() > 0) {
Set<String> supportedTypes = ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions();
if (!supportedTypes.contains(str)) {
throw new RpcException("Unsupported client type: " + str);
}
}
return server;
}
}
HeaderExchanger
public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
// DecodeHandler(HeaderExchangeHandler(ExchangeHandlerAdapter))
return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
}
NettyServer
public NettyServer(URL url, ChannelHandler handler) throws RemotingException{
super(url, ChannelHandlers.wrap(handler, ExecutorUtil.setThreadName(url, SERVER_THREAD_POOL_NAME)));
}
ChannelHandlers
protected ChannelHandler wrapInternal(ChannelHandler handler, URL url) {
// extension = ExtensionLoader.getExtensionLoader(Dispatcher.class).getAdaptiveExtension()
// extension = AllDispatcher
return new MultiMessageHandler(new HeartbeatHandler(((Dispatcher)ExtensionLoader.getExtensionLoader(Dispatcher.class).getAdaptiveExtension()).dispatch(handler, url)));
}
AllDispatcher
public class AllDispatcher implements Dispatcher {
public static final String NAME = "all";
public ChannelHandler dispatch(ChannelHandler handler, URL url) {
// AllChannelHandler
return new AllChannelHandler(handler, url);
}
}
所以,服務端完整的 handler
鏈路為:
MultiMessageHandler
-> HeartbeatHandler
-> AllChannelHandler
-> DecodeHandler
-> HeaderExchangeHandler
-> ExchangeHandlerAdapter
接收訊息流程
NettyHandler
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), this.url, this.handler);
try {
// 呼叫MultiMessageHandler處理
this.handler.received(channel, e.getMessage());
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.getChannel());
}
}
MultiMessageHandler
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 {
// 呼叫HeartbeatHandler處理
handler.received(channel, message);
}
}
HeartbeatHandler
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(
new StringBuilder(32)
.append("Receive heartbeat response in thread ")
.append(Thread.currentThread().getName())
.toString());
}
return;
}
// 呼叫AllChannelHandler處理
handler.received(channel, message);
}
AllChannelHandler
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) {
throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);
}
}
ChannelEventRunnable
public void run() {
switch (state) {
case CONNECTED:
try{
handler.connected(channel);
}catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case DISCONNECTED:
try{
handler.disconnected(channel);
}catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel, e);
}
break;
case SENT:
try{
handler.sent(channel,message);
}catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is "+ message,e);
}
break;
case RECEIVED:
try{
// 呼叫DecodeHandler處理
handler.received(channel, message);
}catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is " + channel
+ ", message is "+ message,e);
}
break;
case CAUGHT:
try{
handler.caught(channel, exception);
}catch (Exception e) {
logger.warn("ChannelEventRunnable handle " + state + " operation error, channel is "+ channel
+ ", message is: " + message + ", exception is " + exception,e);
}
break;
default:
logger.warn("unknown state: " + state + ", message is " + message);
}
}
DecodeHandler
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());
}
// 呼叫HeaderExchangeHandler處理
handler.received(channel, message);
}
HeaderExchangeHandler
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()) {
// 處理請求
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);
}
}
// HeaderExchangeHandler
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();
try {
// handle data.
Object result = handler.reply(channel, msg);
res.setStatus(Response.OK);
res.setResult(result);
} catch (Throwable e) {
res.setStatus(Response.SERVICE_ERROR);
res.setErrorMessage(StringUtils.toString(e));
}
return res;
}
DubboProtocol
成員變數 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);
//如果是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());
// invoker -> Filter(Listener(InvokerDelegete(AbstractProxyInvoker (Wrapper.invokeMethod)))
return invoker.invoke(inv);
}
throw new RemotingException(channel, "Unsupported request: " + message == null ? null : (message.getClass().getName() + ": " + message) + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}
服務端接收訊息流程完成。
相關文章
- Dubbo原始碼解析之服務叢集原始碼
- Dubbo原始碼解析之服務引入過程原始碼
- Dubbo原始碼解析之服務呼叫過程原始碼
- Dubbo原理和原始碼解析之服務引用原始碼
- Dubbo服務暴露原始碼解析②原始碼
- Dubbo原始碼之服務端的釋出原始碼服務端
- Dubbo原始碼解析之客戶端初始化及服務呼叫原始碼客戶端
- Dubbo原始碼解析之服務匯出過程原始碼
- Dubbo原始碼之服務引用原始碼
- Dubbo原始碼解析之服務釋出與註冊原始碼
- Dubbo服務呼叫過程原始碼解析④原始碼
- Dubbo原始碼分析(五)Dubbo呼叫鏈-服務端原始碼服務端
- Dubbo原始碼分析之服務引用原始碼
- Dubbo原始碼分析之服務暴露原始碼
- Dubbo原始碼解析之SPI原始碼
- netty原始碼分析之服務端啟動全解析Netty原始碼服務端
- Spring Cloud系列(三):Eureka原始碼解析之服務端SpringCloud原始碼服務端
- Dubbo原始碼學習之-服務匯出原始碼
- Dubbo2.7.3版本原始碼學習系列六: Dubbo服務匯出原始碼解析原始碼
- 美團Cat原始碼淺析(四)服務端訊息分發原始碼服務端
- dubbo服務者原始碼分期原始碼
- Dubbo原始碼解析之SPI機制原始碼
- dubbo原始碼解析之ExtensionLoader類(二)原始碼
- dubbo原始碼解析之基礎篇原始碼
- dubbo原始碼解析之負載均衡原始碼負載
- 聊聊Dubbo(九):核心原始碼-服務端啟動流程2原始碼服務端
- 聊聊Dubbo(九):核心原始碼-服務端啟動流程1原始碼服務端
- dubbo原始碼分析02:服務引用原始碼
- Dubbo原始碼分析十一、服務路由原始碼路由
- Dubbo原始碼分析(三)Dubbo的服務引用Refer原始碼
- Netty原始碼解析 -- 服務端啟動過程Netty原始碼服務端
- RocketMQ原始碼解析之訊息消費者(consume Message)MQ原始碼
- [原始碼解析] 訊息佇列 Kombu 之 基本架構原始碼佇列架構
- Dubbo原始碼解析之負載均衡策略原始碼負載
- Dubbo原始碼分析(七)服務目錄原始碼
- Flutter 安卓 Platform 與 Dart 端訊息通訊方式 Channel 原始碼解析Flutter安卓PlatformDart原始碼
- dubbo原始碼解析(三十)遠端呼叫——rest協議原始碼REST協議
- vscode原始碼分析【七】主程式啟動訊息通訊服務VSCode原始碼