dubbox和dubbo 2.x是兼容的,没有改变dubbo的任何已有的功能和配置方式(除了升级了spring之类的版本),但是实际上确实不能相互兼容相互调用服务。
其实不兼容的原因是因为服务端受理请求时,在DecodeableRpcInvocation这个类出现异常,异常出线的行数106行 :
出现异常的原因报文解析decode异常。这个要了解dubbo协议的报文格式。
in 对象执行read操作,会一个一个偏移读取报文dubbox提供的服务,当执行该行时,认为报文应该是一个整数,但是确是一个String,解析异常。 所以尝试对DecodeableRpcInvocation类进行了兼容处理:
修改的类如下所示:
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.rpc.protocol.dubbo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.serialize.Cleanable;
import com.alibaba.dubbo.common.serialize.ObjectInput;
import com.alibaba.dubbo.common.serialize.OptimizedSerialization;
import com.alibaba.dubbo.common.serialize.support.kryo.KryoSerialization;
import com.alibaba.dubbo.common.utils.Assert;
import com.alibaba.dubbo.common.utils.ReflectUtils;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.remoting.Channel;
import com.alibaba.dubbo.remoting.Codec;
import com.alibaba.dubbo.remoting.Decodeable;
import com.alibaba.dubbo.remoting.exchange.Request;
import com.alibaba.dubbo.remoting.transport.CodecSupport;
import com.alibaba.dubbo.rpc.RpcInvocation;
import static com.alibaba.dubbo.rpc.protocol.dubbo.CallbackServiceCodec.decodeInvocationArgument;
/**
* @author kimi
*/
public class DecodeableRpcInvocation extends RpcInvocation implements Codec, Decodeable {
private static final Logger log = LoggerFactory.getLogger(DecodeableRpcInvocation.class);
private Channel channel;
private byte serializationType;
private InputStream inputStream;
private Request request;
private volatile boolean hasDecoded;
public DecodeableRpcInvocation(Channel channel, Request request, InputStream is, byte id) {
Assert.notNull(channel, "channel == null");
Assert.notNull(request, "request == null");
Assert.notNull(is, "inputStream == null");
this.channel = channel;
this.request = request;
this.inputStream = is;
this.serializationType = id;
}
public void decode() throws Exception {
if (!hasDecoded && channel != null && inputStream != null) {
try {
decode(channel, inputStream);
} catch (Throwable e) {
if (log.isWarnEnabled()) {
log.warn("Decode rpc invocation failed: " + e.getMessage(), e);
}
request.setBroken(true);
request.setData(e);
} finally {
hasDecoded = true;
}
}
}
public void encode(Channel channel, OutputStream output, Object message) throws IOException {
throw new UnsupportedOperationException();
}
public Object decode(Channel channel, InputStream input) throws IOException {
ObjectInput in = CodecSupport.getSerialization(channel.getUrl(), serializationType)
.deserialize(channel.getUrl(), input);
try {
setAttachment(Constants.DUBBO_VERSION_KEY, in.readUTF());
setAttachment(Constants.PATH_KEY, in.readUTF());
setAttachment(Constants.VERSION_KEY, in.readUTF());
setMethodName(in.readUTF());
try {
Object[] args;
Class>[] pts;
// NOTICE modified by lishen
// 兼容dubbo2.X begin.
String dubboVerson=getAttachment(Constants.DUBBO_VERSION_KEY);
if ("2.5.4".equals(dubboVerson) || "2.5.3".equals(dubboVerson)) {
String desc=in.readUTF();
if (desc.length() == 0) {
pts=DubboCodec.EMPTY_CLASS_ARRAY;
args=DubboCodec.EMPTY_OBJECT_ARRAY;
} else {
pts=ReflectUtils.desc2classArray(desc);
args=new Object[pts.length];
for (int i=0; i < args.length; i++) {
try {
args[i]=in.readObject(pts[i]);
} catch (Exception e) {
if (log.isWarnEnabled()) {
log.warn("Decode argument failed: " + e.getMessage(), e);
}
}
}
}
} // 兼容dubbo2.X end.
else {
int argNum=in.readInt();
if (argNum >= 0) {
if (argNum == 0) {
pts=DubboCodec.EMPTY_CLASS_ARRAY;
args=DubboCodec.EMPTY_OBJECT_ARRAY;
} else {
args=new Object[argNum];
pts=new Class[argNum];
for (int i=0; i < args.length; i++) {
try {
args[i]=in.readObject();
pts[i]=args[i].getClass();
} catch (Exception e) {
if (log.isWarnEnabled()) {
log.warn("Decode argument failed: " + e.getMessage(), e);
}
}
}
}
} else {
String desc=in.readUTF();
if (desc.length() == 0) {
pts=DubboCodec.EMPTY_CLASS_ARRAY;
args=DubboCodec.EMPTY_OBJECT_ARRAY;
} else {
pts=ReflectUtils.desc2classArray(desc);
args=new Object[pts.length];
for (int i=0; i < args.length; i++) {
try {
args[i]=in.readObject(pts[i]);
} catch (Exception e) {
if (log.isWarnEnabled()) {
log.warn("Decode argument failed: " + e.getMessage(), e);
}
}
}
}
}
}
setParameterTypes(pts);
Map map=(Map) in.readObject(Map.class);
if (map != null && map.size() > 0) {
Map attachment=getAttachments();
if (attachment == null) {
attachment=new HashMap();
}
attachment.putAll(map);
setAttachments(attachment);
}
//decode argument ,may be callback
for (int i=0; i < args.length; i++) {
args[i]=decodeInvocationArgument(channel, this, pts, i, args[i]);
}
setArguments(args);
} catch (ClassNotFoundException e) {
throw new IOException(StringUtils.toString("Read invocation data failed.", e));
}
} finally {
// modified by lishen
if (in instanceof Cleanable) {
((Cleanable) in).cleanup();
}
}
return this;
}
}
修改完这块代码打成jar包重新定义dubbo版本为3.8.4,这样的方式可以解决的问题是2,5.3可以消费3.8.4的服务,但是3.8.4不能消费2.5.3的服务,所以作为服务的提供方,应该升到3.8.4,如果仅仅是消费服务而不提供服务,可以用低版本的dubbo