最近忙于业务迭代开发,没有太多时间思考。这两天,开发的时候遇到了一个hessian 序列化异常,拿出来记录一下分析的过程及解决方法。
先上异常,
2016-06-01 10:59:37 New I/O server worker #1-1 WARN [com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation:112] - [DUBBO] Decode argument failed: com.apricotforest.casefolder.medical.search.vo.MedicalRecordSearchVo.tagId: expected integer at 0x24 [B ([B@1e919697), dubbo version: 2.5.3, current host: 192.168.10.23com.alibaba.com.caucho.hessian.io.HessianFieldException: com.apricotforest.casefolder.medical.search.vo.MedicalRecordSearchVo.tagId: expected integer at 0x24 [B ([B@1e919697) at com.alibaba.com.caucho.hessian.io.JavaDeserializer.logDeserializeError(JavaDeserializer.java:671) at com.alibaba.com.caucho.hessian.io.JavaDeserializer$ObjectFieldDeserializer.deserialize(JavaDeserializer.java:400) at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:233) at com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:157) 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.dubbo.common.serialize.support.hessian.Hessian2ObjectInput.readObject(Hessian2ObjectInput.java:94) at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:109) at com.alibaba.dubbo.rpc.protocol.dubbo.DecodeableRpcInvocation.decode(DecodeableRpcInvocation.java:71) at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCodec.decodeBody(DubboCodec.java:137) at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:126) at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.decode(ExchangeCodec.java:87) at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCountCodec.decode(DubboCountCodec.java:46) at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalDecoder.messageReceived(NettyCodecAdapter.java:134) at org.jboss.netty.channel.SimpleChannelUpstreamHandler.handleUpstream(SimpleChannelUpstreamHandler.java:80) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:564) at org.jboss.netty.channel.DefaultChannelPipeline.sendUpstream(DefaultChannelPipeline.java:559) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274) at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:261) at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:349) at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:280) at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:200) at org.jboss.netty.util.ThreadRenamingRunnable.run(ThreadRenamingRunnable.java:108) at org.jboss.netty.util.internal.DeadLockProofWorker$1.run(DeadLockProofWorker.java:44) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Caused by: com.alibaba.com.caucho.hessian.io.HessianProtocolException: expected integer at 0x24 [B ([B@1e919697) at com.alibaba.com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2720) at com.alibaba.com.caucho.hessian.io.Hessian2Input.expect(Hessian2Input.java:2691) at com.alibaba.com.caucho.hessian.io.Hessian2Input.readInt(Hessian2Input.java:773) at com.alibaba.com.caucho.hessian.io.Hessian2Input.readType(Hessian2Input.java:2296) at com.alibaba.com.caucho.hessian.io.BasicDeserializer.readObject(BasicDeserializer.java:251) at com.alibaba.com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1696) at com.alibaba.com.caucho.hessian.io.JavaDeserializer$ObjectFieldDeserializer.deserialize(JavaDeserializer.java:396) ... 26 more
看到这段异常,分分钟想到了dubbo序列化默认用的是hessian,而hessian处理复杂对象时爆出的异常,不太好理解,于是写出一个测试类模拟了一下hessian 序列化/反序列化
package com.apricotforest.casefolder.medical.utils; import com.alibaba.com.caucho.hessian.io.HessianSerializerInput; import com.alibaba.com.caucho.hessian.io.HessianSerializerOutput; import com.apricotforest.casefolder.medical.search.vo.MedicalRecordSearchVo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; /** * Created by on 16/5/31. */ public class HessianSerializeUtil { /** * 纯hessian序列化 * * @param object * @return * @throws Exception */ public static byte[] serialize(Object object) throws Exception { if (null == object) { throw new NullPointerException(); } ByteArrayOutputStream os = new ByteArrayOutputStream(); HessianSerializerOutput hessianOutput = new HessianSerializerOutput(os); hessianOutput.writeObject(object); return os.toByteArray(); } /** * 纯hessian反序列化 * * @param bytes * @return * @throws Exception */ public static Object deserialize(byte[] bytes) throws Exception { if (bytes == null) { throw new NullPointerException(); } ByteArrayInputStream is = new ByteArrayInputStream(bytes); HessianSerializerInput hessianInput = new HessianSerializerInput(is); Object object = hessianInput.readObject(); return object; } public static void main(String[] args) throws Exception { byte[] bytes; // String[] arr = {"6eb90e77-f37-4daf-8665-fc56951f9a25", // "aedf9088-899c-4200-940e-72215b38d258","6142DD32-485A-4393-B757-24B8DC043E99"}; String[] arr = new String[]{"4e2a6912-f4b9-4e04-a999-982ef2bcc64f", "88f4fcc6-43ef-4ccb-8a1a-d50d59313d3a"}; MedicalRecordSearchVo searchVo = new MedicalRecordSearchVo() .setKeyword("ddd").setUserId(2100000005).setTagId(arr); bytes = HessianSerializeUtil.serialize(searchVo); System.out.println("序列化后对象:" + bytes); System.out.println("反序列化后正常属性: " + ((MedicalRecordSearchVo) HessianSerializeUtil.deserialize(bytes)).getKeyword()); System.out.println("反序列号后数组属性: " + ((MedicalRecordSearchVo) HessianSerializeUtil.deserialize(bytes)).getTagId()[0]); } }
本地序列化后,发现数据可以正常反序列化,深入异常,查看异常所对应的代码块,调用栈如下
仔细查看服务调用方传过来的数据,发现类型不匹配导致,升级依赖客户端即可
ps:dubbo 接口联调过程,需要在本地联调,但是本地环境和开发环境共用一个zk,所以使用dubbo 控制台,对开发环境接口降权或添加白名单策略