您的位置:首页 > 其它

使用dubbo自定义返回对象异常

2016-11-24 16:49 671 查看
最近修改了dubbo服务端的返回对象,引用了spring-data-commons中的Page接口,还是使用默认的dubbo协议,也就是netty+hessian2;当消费端连接过来获取数据时,报了下面这个异常

Caused by: com.alibaba.com.caucho.hessian.io.HessianProtocolException: 'org.springframework.data.domain.PageImpl' could not be instantiated
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.instantiate(JavaDeserializer.java:275)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:155)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObjectInstance(Hessian2Input.java:2067)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1592)
at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1576)
at com.alibaba.com.caucho.hessian.io.JavaDeserializer$ObjectFieldDeserializer.deserialize(JavaDeserializer.java:396)
... 29 more


上网查过后发现hessian反序列化:

参数及返回值需实现Serializable接口

参数及返回值需有无参构造函数(可以是private的)或者有参构造所有函数允许传入null值。

而Page接口的实现类PageImpl继承的抽象父类Chunk并未提供无参构造函数,也可以通过查看源码com.alibaba.com.caucho.hessian.io.JavaDeserializer

/**
* Creates a map of the classes fields.
*/
protected static Object getParamArg(Class cl)
{
if (! cl.isPrimitive())
return null;
else if (boolean.class.equals(cl))
return Boolean.FALSE;
else if (byte.class.equals(cl))
return new Byte((byte) 0);
else if (short.class.equals(cl))
return new Short((short) 0);
else if (char.class.equals(cl))
return new Character((char) 0);
else if (int.class.equals(cl))
return Integer.valueOf(0);
else if (long.class.equals(cl))
return Long.valueOf(0);
else if (float.class.equals(cl))
return Float.valueOf(0);
else if (double.class.equals(cl))
return Double.valueOf(0);
else
throw new UnsupportedOperationException();
}


由于PageImpl的两个构造函数的参数都不是基本类型,因此_constructorArgs所包含的值全部是null。

知道问题所在了,那么我们只需更改传输的序列化方式,下面给出两种解决方案让我们还可以用到spring-data-commons中的Page接口:

1、dubbo的序列化使用除了hessian2的其他序列化方式,测试的序列化框架有kryo、fastJson,发现如果用fastJson作为序列化的话,不报错能正常返回,但是data数据是空的;所以推荐使用kryo,也是一种非常高效的序列化框架,其他的可以自行测试。dubbo自带实现有的序列化方式在包com.alibaba.dubbo.common.serialize.support下,当然你也参考官方文档自行实现序列化扩展,比如protobuf。

序列化扩展示例



服务端dubbo增加配置如下:

<dubbo:protocol name="dubbo" port="20088" serialization="kryo"/>


客户端dubbo增加配置如下:

<dubbo:protocol serialization="kryo"/>


2、改用其他协议,比如rmi,hessian,http

服务端dubbo修改配置如下:

<dubbo:protocol name="rmi" port="1090"/>
<dubbo:protocol name="hessian" port="8282"/>

<!-- 下面就可以引用传输协议了 -->
<dubbo:service interface="xxx.xx.x.TestService" ref="testService" protocol="hessian,rmi"/>


客户端dubbo修改配置如下:

<!-- protocol可选服务端提供的hessian,rmi -->
<dubbo:reference id="testService" interface="xxx.xx.x.TestService" protocol="hessian"/>


推荐第一种,毕竟默认的dubbo协议还是在数据小但是高并发的情况下有优势的。

4000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dubbo HessianFie 异常