說完調用的消費端,下面該說說請求到了服務端,是怎么處理的了。首先讓我們回顧下服務端服務發布模型圖
根據netty通信的知識和模型圖,我們知道此時服務端接收到消息會調用NettyServerHandler的channelRead方法
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());
}
}
貌似和消費端上章我們分析端類似,依次類推,我們一樣會找到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) {
//TODO 臨時解決線程池滿后異常信息無法發送到對端的問題。待重構
//fix 線程池滿了拒絕調用不返回,導致消費者一直等待超時
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);
}
}
一樣的邏輯,通過ChannelEventRunnable異步線程進行消息處理,按模型圖走,一樣會走到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);
}
}
處理邏輯
if (request.isTwoWay()) {
Response response = handleRequest(exchangeChannel, request);
channel.send(response);
} else {
handler.received(exchangeChannel, request.getData());
}
當是雙向時會調用有返回結果到方法handleRequest
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;
}
這時候我們看到new了一個Response類,他到id就是request到id,對應上我們消費端返回時到雙線程通信問題了。最后調用落到 handler.reply(channel, msg)方法,模型圖顯示到了DubboProtocol$requestHandler類中
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
//獲取通道緩存對應的invoker
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());
}
我們可以看到, Invoker<?> invoker = getInvoker(channel, inv)方法去獲取了我們發布時生成的invoker,這個invoker是誰?對,就是緩存在exporterMap的DubboExporter重點invoker對象
Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
.......
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();
}
找到它就好辦了,結合模型圖和我們分析的發布知識,我們可以看到
最后調用了當時proxyFactory生成的抽象類中
return new AbstractProxyInvoker<T>(proxy, type, url) {
@Override
protected Object doInvoke(T proxy, String methodName,
Class<?>[] parameterTypes,
Object[] arguments) throws Throwable {
return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
}
};
而此類的實際調用者是我們生成的一個泛式的wrapper
public class Wrapper1 extends Wrapper {
public static String[] pns;
public static java.util.Map pts;
public static String[] mns = new String[]{"sayHello"};
public static String[] dmns = new String[]{"sayHello"};
public static Class[] mts0;
public String[] getPropertyNames() {
return pns;
}
public boolean hasProperty(String n) {
return pts.containsKey(n);
}
public Class getPropertyType(String n) {
return (Class) pts.get(n);
}
public String[] getMethodNames() {
return mns;
}
public String[] getDeclaredMethodNames() {
return dmns;
}
public void setPropertyValue(Object o, String n, Object v) {
com.alibaba.dubbo.kai.api.imp.HelloApiImpl w;
try {
w = ((com.alibaba.dubbo.kai.api.imp.HelloApiImpl) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class com.alibaba.dubbo.kai.api.imp.HelloApiImpl.");
}
public Object getPropertyValue(Object o, String n) {
com.alibaba.dubbo.kai.api.imp.HelloApiImpl w;
try {
w = ((com.alibaba.dubbo.kai.api.imp.HelloApiImpl) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class com.alibaba.dubbo.kai.api.imp.HelloApiImpl.");
}
public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
com.alibaba.dubbo.kai.api.imp.HelloApiImpl w;
try {
w = ((com.alibaba.dubbo.kai.api.imp.HelloApiImpl) o);
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
try {
//和cglib寫法類似,不通過反射調用,效率更高
if ("sayHello".equals(n) && p.length == 0) {
return w.sayHello();
}
} catch (Throwable e) {
throw new java.lang.reflect.InvocationTargetException(e);
}
throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + n + "\" in class com.alibaba.dubbo.kai.api.imp.HelloApiImpl.");
}
}
調用他的invokeMethod方法,顯示最后直接調用了ref(我們實際業務對象)的相應方法,最后返回業務結果。
獲取到結果后,我們返回到HeaderExchangeHandler到received方法
Response response = handleRequest(exchangeChannel, request);
channel.send(response);
下面就是發送結果了,那么根據我們的分析channel應該是對應的NettyChannel
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//包裝后的NettyChannel
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);
try {
handler.received(channel, msg);
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.channel());
}
}
調用NettyChannel的send方法
public void send(Object message, boolean sent) throws RemotingException {
super.send(message, sent);
boolean success = true;
int timeout = 0;
try {
ChannelFuture future = channel.writeAndFlush(message);
if (sent) {
timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
success = future.await(timeout);
}
Throwable cause = future.cause();
if (cause != null) {
throw cause;
}
} catch (Throwable e) {
throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e);
}
if (!success) {
throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress()
+ "in timeout(" + timeout + "ms) limit");
}
}
這就和上一章一樣,且對應上了上章的消費端接收。
到此,調用的消費端和服務端我們就都分析完了。最后再回到我們開章的調用時序圖,就基本已經分析完了。
好了,dubbo基本調用完成,但其中我們還有些遺留
- 負載均衡算法
- 各個filter實現作用
- 其他協議但實現概覽
- 監控但實現
- 其他注冊中心的實現
以后有時間大家再一起學習下其他內容。
下一章 ??? 手寫dubbo核心調用
首頁 ??? dubbo源碼欣賞簡介