大家好,我是烤鸭:
使用dubbo的时候,遇到如下的问题。
Serialized class com.xxx.xxxService must implement java.io.Serializable
1. 异常
dubbo无论使用哪个协议传递参数的时候,都需要参数实现序列化接口。
所以提示这个很大原因在于传递的参数没有实现序列化,但是一般都提示参数,为什么提示service 没有实现序列化。
以下是我使用test方法时的异常信息。
com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method updateObuStatus in the service com.etc.service.car.RpcEtcCarInfoService. Tried 3 times of the providers [168.1.1.68:20888] (1/1) from the registry 168.1.1.26:2181 on the consumer 192.168.191.1 using the dubbo version 2.6.2. Last error is: Failed to invoke remote method: updateObuStatus, provider: dubbo://168.1.1.68:20888/com.etc.service.car.RpcEtcCarInfoService?anyhost=true&application=etc-highway-card&check=false&default.timeout=600000&dubbo=2.6.2&generic=false&interface=com.etc.service.car.RpcEtcCarInfoService&methods=updateCarStatus,queryCustomerInfoByCar,zolCreditQuery,updateObuStatus&pid=61936®ister.ip=192.168.191.1&remote.timestamp=1572940684076&revision=2.2.0&side=consumer&timeout=60000×tamp=1572998190117, cause: Failed to send message Request [id=2, version=2.0.0, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=updateObuStatus, parameterTypes=[class com.etc.dto.UpdateObuStatusRequest], arguments=[UpdateObuStatusRequest(carNum=111, vehicleNo=null, vehicleColor=null, tenantId=null, obuActiveTime=null, obuActiveNo=1111, remark=null)], attachments={path=com.etc.service.car.RpcEtcCarInfoService, interface=com.etc.service.car.RpcEtcCarInfoService, version=0.0.0, timeout=60000}]] to /168.1.1.68:20888, cause: Serialized class com.etc.highway.CreditLogServiceTest must implement java.io.SerializableJava field: final com.etc.highway.CreditLogServiceTest com.etc.highway.CreditLogServiceTest$1.this$0at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:102)at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:238)at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:75)at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)at com.alibaba.dubbo.common.bytecode.proxy13.updateObuStatus(proxy13.java)at com.etc.highway.CreditLogServiceTest.getOfflineDataList(CreditLogServiceTest.java:41)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)at org.junit.runners.ParentRunner.run(ParentRunner.java:363)at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)at org.junit.runner.JUnitCore.run(JUnitCore.java:137)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: com.alibaba.dubbo.remoting.RemotingException: Failed to send message Request [id=2, version=2.0.0, twoway=true, event=false, broken=false, data=RpcInvocation [methodName=updateObuStatus, parameterTypes=[class com.etc.dto.UpdateObuStatusRequest], arguments=[UpdateObuStatusRequest(carNum=111, vehicleNo=null, vehicleColor=null, tenantId=null, obuActiveTime=null, obuActiveNo=1111, remark=null)], attachments={path=com.etc.service.car.RpcEtcCarInfoService, interface=com.etc.service.car.RpcEtcCarInfoService, version=0.0.0, timeout=60000}]] to /168.1.1.68:20888, cause: Serialized class com.etc.highway.CreditLogServiceTest must implement java.io.SerializableJava field: final com.etc.highway.CreditLogServiceTest com.etc.highway.CreditLogServiceTest$1.this$0at com.alibaba.dubbo.remoting.transport.netty.NettyChannel.send(NettyChannel.java:110)at com.alibaba.dubbo.remoting.transport.AbstractClient.send(AbstractClient.java:265)at com.alibaba.dubbo.remoting.transport.AbstractPeer.send(AbstractPeer.java:53)at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeChannel.request(HeaderExchangeChannel.java:115)at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeClient.request(HeaderExchangeClient.java:90)at com.alibaba.dubbo.rpc.protocol.dubbo.ReferenceCountExchangeClient.request(ReferenceCountExchangeClient.java:83)at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:95)at com.alibaba.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:148)at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)at com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:54)at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)at com.alibaba.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:48)at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:72)at com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:77)at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:56)at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:78)... 35 more
Caused by: java.lang.RuntimeException: Serialized class com.etc.highway.CreditLogServiceTest must implement java.io.SerializableJava field: final com.etc.highway.CreditLogServiceTest com.etc.highway.CreditLogServiceTest$1.this$0at com.alibaba.com.caucho.hessian.io.JavaSerializer$FieldSerializer.serialize(JavaSerializer.java:300)at com.alibaba.com.caucho.hessian.io.JavaSerializer.writeInstance(JavaSerializer.java:280)at com.alibaba.com.caucho.hessian.io.JavaSerializer.writeObject(JavaSerializer.java:247)at com.alibaba.com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:391)at com.alibaba.dubbo.common.serialize.hessian2.Hessian2ObjectOutput.writeObject(Hessian2ObjectOutput.java:88)at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCodec.encodeRequestData(DubboCodec.java:176)at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.encodeRequest(ExchangeCodec.java:234)at com.alibaba.dubbo.remoting.exchange.codec.ExchangeCodec.encode(ExchangeCodec.java:71)at com.alibaba.dubbo.rpc.protocol.dubbo.DubboCountCodec.encode(DubboCountCodec.java:38)at com.alibaba.dubbo.remoting.transport.netty.NettyCodecAdapter$InternalEncoder.encode(NettyCodecAdapter.java:80)at org.jboss.netty.handler.codec.oneone.OneToOneEncoder.handleDownstream(OneToOneEncoder.java:66)at com.alibaba.dubbo.remoting.transport.netty.NettyHandler.writeRequested(NettyHandler.java:98)at org.jboss.netty.channel.Channels.write(Channels.java:611)at org.jboss.netty.channel.Channels.write(Channels.java:578)at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:251)at com.alibaba.dubbo.remoting.transport.netty.NettyChannel.send(NettyChannel.java:100)... 51 more
Caused by: java.lang.IllegalStateException: Serialized class com.etc.highway.CreditLogServiceTest must implement java.io.Serializableat com.alibaba.com.caucho.hessian.io.SerializerFactory.getDefaultSerializer(SerializerFactory.java:395)at com.alibaba.com.caucho.hessian.io.SerializerFactory.getSerializer(SerializerFactory.java:369)at com.alibaba.com.caucho.hessian.io.Hessian2Output.writeObject(Hessian2Output.java:389)at com.alibaba.com.caucho.hessian.io.JavaSerializer$FieldSerializer.serialize(JavaSerializer.java:298)... 66 more
2. 分析
极大的可能在于service用了rpc中的request对象构建了匿名内部类。
所以提示 Java field: final xxx.this$0
JDK8 以后,匿名内部类默认用 final 修饰。
这个 UpdateObuStatusRequest 是本来rpc-api的jar中的需要传参数的对象,错误代码如下,但是在调用的时候,使用了匿名内部类。
@Autowiredprivate RpcEtcCarInfoService rpcEtcCarInfoService;@Testpublic void test() throws InterruptedException {// 2.通知teacherUpdateObuStatusRequest updateObuStatusRequest = new UpdateObuStatusRequest() {{this.setCarNum("111");this.setObuActiveNo("1111");}};ExterResponse exterResponse = rpcEtcCarInfoService.updateObuStatus(updateObuStatusRequest);System.out.println(JSON.toJSONString(exterResponse));}
跟了下源码,可以看到的是。在使用netty进行 消息发送的时候,对参数进行序列化,用反射获取的是匿名内部类的对应的当前类的对象。刚调用 send 方法的时候,看到的request 对象的参数是对的。
进行序列化的时候。发现这个object是当前测试类的对象。
好吧,下次注意。另外不建议匿名内部类的写法。
由于创建的对象用final 修饰后,直接进入了常量池,生存时间不再和调用方法是一样的,容易造成 leak memory(内存泄露)。