dubbo远程调用的源码分析,分成了三篇文章地址分别如下:
下面是consumer接收到provider反馈时的处理
consumer接收到provider的反馈后,触发NettyClient的事件处理器,该事件对consumer来说是上行事件,触发的是NettyCodecAdapter.DeCoder和NettyHandler
首先是NettyCodecAdapter.DeCoder,调用的是NettyCodecAdapter中的InternalDecoder类的messageReceived()方法:
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);
}
}
和consumer给provider发送消息时调用的是一个方法,方法最后调用了Codec2.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 magic number.
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);
}
// check length.
if (readable< HEADER_LENGTH) {
return DecodeResult.NEED_MORE_INPUT;
}
// get data length.
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);
}
}
}
}
最后return的decodeBody()方法在DubboCodec类中实现:
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);
// 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);
}
// get status.
byte status= header[3];
res.setStatus(status);
if (status== Response.OK) {
try {
Object data;
if(res.isHeartbeat()) {
data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(),is));
} else if (res.isEvent()) {
data = decodeEventData(channel, deserialize(s, channel.getUrl(), is));
}else {
DecodeableRpcResult result;
if (channel.getUrl().getParameter(
Constants.DECODE_IN_IO_THREAD_KEY,
Constants.DEFAULT_DECODE_IN_IO_THREAD)) {
result = new DecodeableRpcResult(channel, res, is,
(Invocation) getRequestData(id), proto);
result.decode();
} else {
result = new DecodeableRpcResult(channel, res,
new UnsafeByteArrayInputStream(readMessageData(is)),
(Invocation) getRequestData(id), proto);
}
data = result;
}
res.setResult(data);
} catch(Throwable t) {
if(log.isWarnEnabled()) {
log.warn("Decode response failed: " + t.getMessage(), t);
}
res.setStatus(Response.CLIENT_ERROR);
res.setErrorMessage(StringUtils.toString(t));
}
} else {
res.setErrorMessage(deserialize(s, channel.getUrl(), is).readUTF());
}
return res;
} else {
// decode request.
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 {
Object data;
if(req.isHeartbeat()) {
data = decodeHeartbeatData(channel, deserialize(s, channel.getUrl(),is));
} else if (req.isEvent()) {
data = decodeEventData(channel, deserialize(s, channel.getUrl(), is));
} else{
DecodeableRpcInvocation inv;
if(channel.getUrl().getParameter(
Constants.DECODE_IN_IO_THREAD_KEY,
Constants.DEFAULT_DECODE_IN_IO_THREAD)) {
inv = new DecodeableRpcInvocation(channel, req, is, proto);
inv.decode();
}else {
inv = new DecodeableRpcInvocation(channel, req,
new UnsafeByteArrayInputStream(readMessageData(is)), proto);
}
data = inv;
}
req.setData(data);
} catch(Throwable t) {
if(log.isWarnEnabled()) {
log.warn("Decode request failed: " + t.getMessage(), t);
}
// bad request
req.setBroken(true);
req.setData(t);
}
return req;
}
}
provider解析consumer发来的消息时调用的是方法中decode request部分,现在consumer接收provider消息,调用的是方法的decode response部分
首先创建了一个Response对象,从header中得到Response状态,如果status不是OK,则在Response设置ErrorMessage,否则,创建一个DecodeableRpcResult对象,然后调用他的decode()方法
DecodeableRpcResult的decode()方法如下:
public Object decode(Channel channel, InputStream input) throws IOException {
ObjectInput in= CodecSupport.getSerialization(channel.getUrl(), serializationType)
.deserialize(channel.getUrl(), input);
byte flag =in.readByte();
switch (flag) {
case DubboCodec.RESPONSE_NULL_VALUE:
break;
case DubboCodec.RESPONSE_VALUE:
try {
Type[] returnType = RpcUtils.getReturnTypes(invocation);
setValue(returnType == null || returnType.length == 0 ? in.readObject():
(returnType.length == 1 ? in.readObject((Class<?>) returnType[0])
:in.readObject((Class<?>) returnType[0], returnType[1])));
} catch(ClassNotFoundException e) {
throw new IOException(StringUtils.toString("Read response datafailed.", e));
}
break;
case DubboCodec.RESPONSE_WITH_EXCEPTION:
try {
Object obj = in.readObject();
if(obj instanceof Throwable == false)
throw new IOException("Response data error, expect Throwable, butget " + obj);
setException((Throwable) obj);
} catch(ClassNotFoundException e) {
throw new IOException(StringUtils.toString("Read response datafailed.", e));
}
break;
default:
throw new IOException("Unknown result flag, expect '0' '1' '2', get " +flag);
}
return this;
}
首先是反序列化,然后判断返回值类型
如果没有返回值类型,也就是flag=DubboCodec.RESPONSE_NULL_VALUE,则直接break退出switch
如果返回值类型里有异常,也就是flag=DubboCodec.RESPONSE_WITH_EXCEPTION,则调用父类的setException()方法,设置Exception属性并退出switch
如果返回值有类型,也就是flag=DubboCodec.RESPONSE_VALUE,则调用父类的setValue()方法设置Value属性然后退出switch
DecodeableRpcResult的父类是RpcResult类。
至此,事件的NettyCodecAdapter.DeCoder部分处理完毕,然后是NettyHandler的处理,调用的是NettyHandler的messageReceived()方法:
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());
}
}
然后是DecodeHandler类的received方法:
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);
}
然后是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是一个Response对象,要调用handleResponse()方法:
static void handleResponse(Channel channel, Response response) throws RemotingException {
if (response !=null && !response.isHeartbeat()) {
DefaultFuture.received(channel, response);
}
}
这个方法的if判断里要求这个response不能是心跳,目测dubbo接口之间的心跳检测也是用这个方法的,这个方法调用了DefaultFuture类的received()方法:
public static void received(Channel channel, Response response) {
try {
DefaultFuture future = FUTURES.remove(response.getId());
if (future!= null) {
future.doReceived(response);
} else {
logger.warn("The timeout response finally returned at "
+ (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(newDate()))
+ ", response " + response
+ (channel == null ? "" : ", channel: " +channel.getLocalAddress()
+ " -> " + channel.getRemoteAddress()));
}
} finally {
CHANNELS.remove(response.getId());
}
}
FUTURES是个<long,DefaultFuture>类型的map,首先从这个map中把这个Response删除,然后调用DefaultFuture的doReceived()方法:
private void doReceived(Response res) {
lock.lock();
try {
response =res;
if (done !=null) {
done.signal();
}
} finally {
lock.unlock();
}
if (callback !=null) {
invokeCallback(callback);
}
}
这个方法中用的lock对象是java的重入锁,是java.util.concurrent.locks.ReentrantLock.ReentrantLock这个类的对象,done对象是lock.newCondition()生成的,是java.util.concurrent.locks.Condition这个类的对象,该方法中调用的done.signal()方法的作用是唤醒consumer的调用线程,这个调用线程是consumer把消息发送给provider之后进入阻塞状态的,让线程进入阻塞状态的方法是DefaultFuture类的get()方法:
public Object get(int timeout) throws RemotingException {
if (timeout<= 0) {
timeout =Constants.DEFAULT_TIMEOUT;
}
if (!isDone()){
long start= System.currentTimeMillis();
lock.lock();
try {
while(!isDone()) {
done.await(timeout, TimeUnit.MILLISECONDS);
if(isDone() || System.currentTimeMillis() - start > timeout) {
break;
}
}
} catch(InterruptedException e) {
throw new RuntimeException(e);
} finally {
lock.unlock();
}
if(!isDone()) {
throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
}
}
return returnFromResponse();
}
其中done.await方法会使线程阻塞,但是不会一直阻塞,如果在设置的超时时间之后线程依然在阻塞状态,则自动唤醒线程,后面的isDone()方法其实只判断了response是否是null,如果线程因为超时而被唤醒,这个时候Response还是null,就会抛出调用超时的异常,最后,调用returnFromResponse方法,返回Response中的result,代码如下:
private Object returnFromResponse() throws RemotingException {
Response res =response;
if (res ==null) {
throw new IllegalStateException("response cannot be null");
}
if(res.getStatus() == Response.OK) {
return res.getResult();
}
if(res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT){
throw new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel,res.getErrorMessage());
}
throw new RemotingException(channel, res.getErrorMessage());
}
该返对象返对象,该返异常返异常,至此dubbo远程调用的过程就结束了。