dubbo远程调用的源码分析,分成了三篇文章地址分别如下:
下面看provider端接收到消息后的处理过程
首先要经过NettyClient的事件处理器,顺序是NettyCodecAdapter.DeCoder和NettyHandler
NettyCodecAdapter的Decoder是在NettyCodecAdapter类中定义的
private class InternalDecoder extends SimpleChannelUpstreamHandler {
private com.alibaba.dubbo.remoting.buffer.ChannelBuffer buffer =
com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) throws Exception{
Object o =event.getMessage();
if (!(o instanceof ChannelBuffer)) {
ctx.sendUpstream(event);
return;
}
ChannelBuffer input = (ChannelBuffer) o;
int readable = input.readableBytes();
if(readable <= 0) {
return;
}
com.alibaba.dubbo.remoting.buffer.ChannelBuffer message;
if(buffer.readable()) {
if(buffer instanceof DynamicChannelBuffer) {
buffer.writeBytes(input.toByteBuffer());
message = buffer;
} else{
int size = buffer.readableBytes() + input.readableBytes();
message =com.alibaba.dubbo.remoting.buffer.ChannelBuffers.dynamicBuffer(
size > bufferSize ? size : bufferSize);
message.writeBytes(buffer, buffer.readableBytes());
message.writeBytes(input.toByteBuffer());
}
} else {
message= com.alibaba.dubbo.remoting.buffer.ChannelBuffers.wrappedBuffer(
input.toByteBuffer());
}
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(),url, handler);
Object msg;
int saveReaderIndex;
try {
//decode object.
do {
saveReaderIndex = message.readerIndex();
try{
msg = codec.decode(channel, message);
}catch (IOException e) {
buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
throw e;
}
if(msg == Codec2.DecodeResult.NEED_MORE_INPUT) {
message.readerIndex(saveReaderIndex);
break;
}else {
if (saveReaderIndex == message.readerIndex()) {
buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
throw new IOException("Decode without read data.");
}
if (msg != null) {
Channels.fireMessageReceived(ctx, msg, event.getRemoteAddress());
}
}
} while(message.readable());
} finally {
if(message.readable()) {
message.discardReadBytes();
buffer= message;
} else{
buffer = com.alibaba.dubbo.remoting.buffer.ChannelBuffers.EMPTY_BUFFER;
}
NettyChannel.removeChannelIfDisconnected(ctx.getChannel());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
ctx.sendUpstream(e);
}
}
其中的messageReceived()方法就是接收消息之后执行的方法
首先从event把接收到的消息读到ChannelBuffer中,然后用Codec2.decode方法解码
Codec2接口由DubboCodec类实现,decode()方法具体是在在DubboCodec的父类ExchangeCodec类中:
public Object decode(Channel channel, ChannelBuffer buffer) throws IOException {
int readable =buffer.readableBytes();
byte[] header =new byte[Math.min(readable, HEADER_LENGTH)];
buffer.readBytes(header);
return decode(channel, buffer, readable, header);
}
最后调用的decode方法如下:
protected Object decode(Channel channel, ChannelBuffer buffer, int readable, byte[] header)throws IOException {
// check magicnumber.
if (readable> 0 && header[0] != MAGIC_HIGH
||readable > 1 && header[1] != MAGIC_LOW) {
int length= header.length;
if(header.length < readable) {
header= Bytes.copyOf(header, readable);
buffer.readBytes(header, length, readable - length);
}
for (int i= 1; i < header.length - 1; i++) {
if(header[i] == MAGIC_HIGH && header[i + 1] == MAGIC_LOW) {
buffer.readerIndex(buffer.readerIndex() - header.length + i);
header = Bytes.copyOf(header, i);
break;
}
}
return super.decode(channel, buffer, readable, header);
}
// checklength.
if (readable< HEADER_LENGTH) {
return DecodeResult.NEED_MORE_INPUT;
}
// get datalength.
int len =Bytes.bytes2int(header, 12);
checkPayload(channel,len);
int tt = len +HEADER_LENGTH;
if (readable< tt) {
return DecodeResult.NEED_MORE_INPUT;
}
// limit inputstream.
ChannelBufferInputStream is = new ChannelBufferInputStream(buffer, len);
try {
return decodeBody(channel, is, header);
} finally {
if(is.available() > 0) {
try {
if(logger.isWarnEnabled()) {
logger.warn("Skip input stream " + is.available());
}
StreamUtils.skipUnusedStream(is);
} catch(IOException e) {
logger.warn(e.getMessage(), e);
}
}
}
}
该方法一开始根据head信息,判断当前接收到的消息是否完整,这个判定是和dubbo的响应机制有关,dubbo读取消息是以事件机制(Event)为基础的,是一种NIO的设计,当事件响应机制得到事件后,信息的传输可能不全,如果不全,则终止该次处理,等消息传输完整后再处理。
如果消息完整,需要解码,调用了decodeBody()方法:
protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException {
byte flag =header[2], proto = (byte) (flag & SERIALIZATION_MASK);
Serialization s= CodecSupport.getSerialization(channel.getUrl(), proto);
ObjectInput in= s.deserialize(channel.getUrl(), is);
// get requestid.
long id =Bytes.bytes2long(header, 4);
if ((flag &FLAG_REQUEST) == 0) {
// decode response.
Response res = new Response(id);
if ((flag& FLAG_EVENT) != 0) {
res.setEvent(Response.HEARTBEAT_EVENT);
}
// getstatus.
byte status= header[3];
res.setStatus(status);
if (status== Response.OK) {
try {
Object data;
if(res.isHeartbeat()) {
data = decodeHeartbeatData(channel, in);
}else if (res.isEvent()) {
data = decodeEventData(channel, in);
}else {
data = decodeResponseData(channel, in, getRequestData(id));
}
res.setResult(data);
} catch(Throwable t) {
res.setStatus(Response.CLIENT_ERROR);
res.setErrorMessage(StringUtils.toString(t));
}
} else {
res.setErrorMessage(in.readUTF());
}
return res;
} else {
// decoderequest.
Request req= new Request(id);
req.setVersion("2.0.0");
req.setTwoWay((flag & FLAG_TWOWAY) != 0);
if ((flag& FLAG_EVENT) != 0) {
req.setEvent(Request.HEARTBEAT_EVENT);
}
try {
Objectdata;
if(req.isHeartbeat()) {
data = decodeHeartbeatData(channel, in);
} else if (req.isEvent()) {
data = decodeEventData(channel, in);
} else{
data = decodeRequestData(channel, in);
}
req.setData(data);
} catch(Throwable t) {
// badrequest
req.setBroken(true);
req.setData(t);
}
return req;
}
}
该方法最开始从header里面获取了flag和proto,并且获取序列化方式,下面有个flag的if判断,是因为provider接收消息和consumer接收provider反馈时都用这段代码,当provider接收消息时,代码走的是else部分,也就是新建了一个Request对象,然后把消息解码,放入Request对象。
得到Request对象后,回到InternalDecoder的messageReceived()方法,codec.decode()方法获得的Request对象赋值给msg,如果消息是完整的而且正常解码了,会调用Channels.fireMessageReceived()方法做一些信息设置,该方法代码如下:
/**
* Sends a {@code"messageReceived"} event to the
* {@linkChannelUpstreamHandler} which is placed in the closest upstream
* from the handlerassociated with the specified
* {@linkChannelHandlerContext}.
*
* @param message the received message
* @param remoteAddress the remote address wherethe received message
* came from
*/
public static void fireMessageReceived(
ChannelHandlerContext ctx, Object message, SocketAddress remoteAddress){
ctx.sendUpstream(new UpstreamMessageEvent(
ctx.getChannel(), message, remoteAddress));
}
至此NettyCodecAdapter.DeCoder结束,下面是NettyHandler,触发的是NettyHandler的messageReceived()方法:
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
NettyChannel channel = NettyChannel.getOrAddChannel(ctx.getChannel(), url, handler);
try {
handler.received(channel, e.getMessage());
} finally {
NettyChannel.removeChannelIfDisconnected(ctx.getChannel());
}
}
其中调用了handler的received()方法,该方法的实现在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());
}
handler.received(channel, message);
}
这里的message是Request,所以走的是第二个if里的判断,这里面是解码,前面已经解码过了,其实不会再解码了,方法的最后是其他handler.received()方法,这个handler的实现类是HeaderExchangeHandler类,他的received()方法如下:
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 stringmessage: " + 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);
}
}
该方法中的message是Request类型,并且request.isTwoWay是true,会调用handleReuqest方法得到处理结果Response,然后用Channel.send()方法把处理结果发送给consumer,下面是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("Failto decode request due to: " + msg);
res.setStatus(Response.BAD_REQUEST);
return res;
}
// find handlerby message class.
Object msg =req.getData();
try {
// handledata.
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;
}
方法创建了一个Response对象,首先判断请求是否有效,无效则会直接返回标识错误的Response,否则从Request中得到封装的对象,然后调用handler.reply()方法,得到结果,这个handler是由DubboProtocol类中定义的ExchangeHandler类实现的,ExchangeHandler实际上是一个ExchangeHandlerAdapter,除了reply方法之外还实现了Channel接口的很多方法比如connected,received等,ExchangeHandler类的定义和reply方法如下:
private ExchangeHandler requestHandler = newExchangeHandlerAdapter() {
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 ,invokewill 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());
}
//还有很多别的方法,此处省略
}
reply方法开始的时候调用getInvoker()方法,得到了Invoker,getInvoker()方法如下:
Invoker<?> getInvoker(Channel channel, Invocation inv) throws RemotingException {
boolean isCallBackServiceInvoke = false;
boolean isStubServiceInvoke = false;
int port =channel.getLocalAddress().getPort();
String path =inv.getAttachments().get(Constants.PATH_KEY);
//如果是客户端的回调服务.
isStubServiceInvoke =Boolean.TRUE.toString().equals(inv.getAttachments().get(Constants.STUB_EVENT_KEY));
if(isStubServiceInvoke) {
port =channel.getRemoteAddress().getPort();
}
//callback
isCallBackServiceInvoke= isClientSide(channel) && !isStubServiceInvoke;
if(isCallBackServiceInvoke) {
path =inv.getAttachments().get(Constants.PATH_KEY) + "." +inv.getAttachments().get(Constants.CALLBACK_SERVICE_KEY);
inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE,Boolean.TRUE.toString());
}
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();
}
这个方法用端口号,接口地址,版本,分组号等信息获取了一个serviceKey,根据这个serviceKey从exporterMap中获得了目标Invoker,实际上这个exporterMap是在provider初始化的时候生成的,放在DubboProtocol的父类AbstractProtocol中,每个接口都会生成一个Exporter对象放在exporterMap里,用端口号、接口地址、版本、分组号当做map的key,Exporter对象会包含一个Invoker对象。
获取serviceKey的方法serviceKey()的代码在DubboProtocol的父类AbstractProtocol中:
protected static String serviceKey(int port, String serviceName, String serviceVersion, StringserviceGroup) {
return ProtocolUtils.serviceKey(port, serviceName, serviceVersion, serviceGroup);
}
ProtocolUtils.serviceKey()方法代码:
public static String serviceKey(int port, String serviceName, String serviceVersion, String serviceGroup) {
StringBuilderbuf = new StringBuilder();
if(serviceGroup != null && serviceGroup.length() > 0) {
buf.append(serviceGroup);
buf.append("/");
}
buf.append(serviceName);
if(serviceVersion != null && serviceVersion.length() > 0 &&!"0.0.0".equals(serviceVersion)) {
buf.append(":");
buf.append(serviceVersion);
}
buf.append(":");
buf.append(port);
return buf.toString();
}
其实就是用各种参数组合成的一个字符串
回到ExchangeHandler类的reply()方法,方法最后调用的invoker.invoke()方法,这个Invoker反射实际的接口实现类并处理信息,使用了工厂模式和动态代理的方式,这里的代理是Javassist代理,工厂代码在JavassistProxyFactory类中,如下:
public class JavassistProxyFactory extends AbstractProxyFactory {
@SuppressWarnings("unchecked")
public <T>T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
return (T)Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}
public <T>Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
// TODO Wrapper类不能正确处理带$的类名
final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ?proxy.getClass() : type);
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);
}
};
}
}
处理完信息并得到返回值后,回到HeaderExchangeHandler类的received()方法,上面的代码就是调用handleRequest()方法获得Response的过程,然后就调用channel.send()方法,把返回值发送给consumer,channel的实现类NettyChannel,他的send方法就是上面consumer给provider发信息的那个方法,
public void send(Object message, boolean sent) throws RemotingException {
super.send(message, sent);
boolean success= true;
int timeout =0;
try {
ChannelFuture future = channel.write(message);
if (sent) {
timeout= getUrl().getPositiveParameter(Constants.TIMEOUT_KEY,Constants.DEFAULT_TIMEOUT);
success= future.await(timeout);
}
Throwable cause = future.getCause();
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");
}
}
其中的channel.write就是发送的方法,在调用这个方法的时候会触发下行事件的事件处理器,也和consumer往provider发消息时一样,触发NettyCodecAdapter.encoder和NettyHandler,只不过此时调用的是DubboCodec的encodeResponse()方法(具体实现在父类ExchangeCodec中),而不是之前的encodeRequest()方法,所以encodeResponse()方法如下:
protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res) throws IOException {
int savedWriteIndex = buffer.writerIndex();
try {
Serialization serialization = getSerialization(channel);
// header.
byte[]header = new byte[HEADER_LENGTH];
// set magic number.
Bytes.short2bytes(MAGIC, header);
// set request and serialization flag.
header[2] =serialization.getContentTypeId();
if(res.isHeartbeat()) header[2] |= FLAG_EVENT;
// set response status.
byte status= res.getStatus();
header[3] =status;
// set request id.
Bytes.long2bytes(res.getId(), header, 4);
buffer.writerIndex(savedWriteIndex + HEADER_LENGTH);
ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer);
ObjectOutput out = serialization.serialize(channel.getUrl(), bos);
// encode response data or error message.
if (status== Response.OK) {
if(res.isHeartbeat()) {
encodeHeartbeatData(channel, out, res.getResult());
} else{
encodeResponseData(channel, out, res.getResult());
}
} else out.writeUTF(res.getErrorMessage());
out.flushBuffer();
bos.flush();
bos.close();
int len =bos.writtenBytes();
checkPayload(channel, len);
Bytes.int2bytes(len, header, 12);
// write
buffer.writerIndex(savedWriteIndex);
buffer.writeBytes(header); // write header.
buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len);
} catch(Throwable t) {
// 将buffer内容清空
buffer.writerIndex(savedWriteIndex);
// 发送失败信息给Consumer,否则Consumer只能等超时了
if(!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) {
Response r = new Response(res.getId(), res.getVersion());
r.setStatus(Response.BAD_RESPONSE);
if (t instanceof ExceedPayloadLimitException) {
logger.warn(t.getMessage(), t);
try{
r.setErrorMessage(t.getMessage());
channel.send(r);
return;
} catch (RemotingException e) {
logger.warn("Failed to send bad_response info back: " +t.getMessage() + ", cause: " + e.getMessage(), e);
}
} else{
//FIXME 在Codec中打印出错日志?在IoHanndler的caught中统一处理?
logger.warn("Fail to encode response: " + res + ", send bad_response info instead, cause: " + t.getMessage(), t);
try{
r.setErrorMessage("Failed to send response: " + res + ",cause: " + StringUtils.toString(t));
channel.send(r);
return;
}catch (RemotingException e) {
logger.warn("Failed to send bad_response info back: " + res +", cause: " + e.getMessage(), e);
}
}
}
// 重新抛出收到的异常
if (t instanceof IOException) {
throw (IOException) t;
} else if(t instanceof RuntimeException) {
throw(RuntimeException) t;
} else if(t instanceof Error) {
throw(Error) t;
} else {
throw new RuntimeException(t.getMessage(), t);
}
}
}
和encodeRequest差不多,拼装消息头,编码,序列化消息体,最后调用encodeResponseData方法,因为这里本身调用的是ExchangeCodec的子类DubboCodec,所以方法中的encodeResponseData方法调用的是DubboCodec重写的方法,代码如下:
@Override
protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException {
Result result =(Result) data;
Throwable th =result.getException();
if (th == null){
Object ret= result.getValue();
if (ret ==null) {
out.writeByte(RESPONSE_NULL_VALUE);
} else {
out.writeByte(RESPONSE_VALUE);
out.writeObject(ret);
}
} else {
out.writeByte(RESPONSE_WITH_EXCEPTION);
out.writeObject(th);
}
}
首先判断结果中否包含异常,没有异常再判断结果中有没有返回值类型,要是没有返回值类型就不写消息体了。
至此provider的处理过程结束