dubbo服务通过Hessianspring proxyfactoryy调用远程接口、第二次调用时会出现异常、

dubbo如何调用hessian或webservice协议暴露的接口??求大神帮助 - 开源中国社区
当前访客身份:游客 [
当前位置:
服务地址:hessian://192.168.1.156:8086/com.houg.puteService?anyhost=true&application=calculator-app&default.timeout=5000&dubbo=2.5.3&dynamic=true&interface=com.houg.puteService&methods=distance,createPoint,add&pid=6296&server=servlet&side=provider×tamp=9
调用代码:
@Reference(url="hessian://192.168.1.156:8086/com.houg.puteService") private ComputeService computeS
com.alibaba.dubbo.rpc.RpcException: Failed to invoke remote service: interface com.houg.puteService, method: add, cause: HessianProxy cannot connect to 'http://192.168.1.156:8086/com.houg.puteService?application=calculator-app&default.timeout=5000&dubbo=2.5.3&interface=com.houg.puteService&methods=distance,createPoint,add&pid=3572&side=consumer×tamp=3
共有0个答案
更多开发者职位上
有什么技术问题吗?
类似的话题简单之美 | 基于Dubbo的Hessian协议实现远程调用
简单之美 | 基于Dubbo的Hessian协议实现远程调用
Dubbo基于Hessian实现了自己Hessian协议,可以直接通过配置的Dubbo内置的其他协议,在服务消费方进行远程调用,也就是说,服务调用方需要使用Java语言来基于Dubbo调用提供方服务,限制了服务调用方。同时,使用Dubbo的Hessian协议实现提供方服务,而调用方可以使用标准的Hessian接口来调用,原生的Hessian协议已经支持多语言客户端调用,支持语言如下所示:
Flash/Flex:
Objective-C:
下面,我们的思路是,先基于Dubbo封装的Hessian协议,实现提供方服务和消费方调用服务,双方必须都使用Dubbo来开发;然后,基于Dubbo封装的Hessian协议实现提供方服务,然后服务消费方使用标准的Hessian接口来进行远程调用,分别使用Java和Python语言来实现。而且,我们实现的提供方服务通过Tomcat发布到服务注册中心。
首先,使用Java语言定义一个搜索服务的接口,代码如下所示:
1package org.shirdrn.platform.dubbo.service.rpc.2&3public interface SolrSearchService {4&&&&String search(String collection, String q, String type, int start, int rows);5}
上面接口提供了搜索远程调用功能。
基于Dubbo的Hessian协议实现提供方服务
提供方实现基于Dubbo封装的Hessian协议,实现接口SolrSearchService,实现代码如下所示:
01package org.shirdrn.platform.dubbo.service.rpc.02&03import java.io.IOE04import java.util.HashM05import java.util.M06&07import mons.logging.L08import mons.logging.LogF09import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchS10import org.shirdrn.platform.dubbo.service.rpc.utils.QueryPostC11import org.springframework.context.support.ClassPathXmlApplicationC12&13public class SolrSearchServer implements SolrSearchService {14&15&&&&private static final Log LOG = LogFactory.getLog(SolrSearchServer.class);16&&&&private String baseU17&&&&private final QueryPostClient postC18&&&&private static final Map&String, FormatHandler& handlers = new HashMap&String, FormatHandler&(0);19&&&&static {20&&&&&&&&handlers.put("xml", new FormatHandler() {21&&&&&&&&&&&&public String format() {22&&&&&&&&&&&&&&&&return "&wt=xml";23&&&&&&&&&&&&}24&&&&&&&&});25&&&&&&&&handlers.put("json", new FormatHandler() {26&&&&&&&&&&&&public String format() {27&&&&&&&&&&&&&&&&return "&wt=json";28&&&&&&&&&&&&}29&&&&&&&&});30&&&&}31&32&&&&public SolrSearchServer() {33&&&&&&&&super();34&&&&&&&&postClient = QueryPostClient.newIndexingClient(null);35&&&&}36&37&&&&public void setBaseUrl(String baseUrl) {38&&&&&&&&this.baseUrl = baseU39&&&&}40&41&&&&public String search(String collection, String q, String type, int start, int rows) {42&&&&&&&&StringBuffer url = new StringBuffer();43&&&&&&&&url.append(baseUrl).append(collection).append("/select?").append(q);44&&&&&&&&url.append("&start=").append(start).append("&rows=").append(rows);45&&&&&&&&url.append(handlers.get(type.toLowerCase()).format());46&&&&&&&&<("[REQ] " + url.toString());47&&&&&&&&return postClient.request(url.toString());48&&&&}49&50&&&&interface FormatHandler {51&&&&&&&&String format();52&&&&}53}
因为考虑到后面要使用标准Hessian接口来调用,这里接口方法参数全部使用内置标准类型。然后,我们使用Dubbo的配置文件进行配置,文件search-provider.xml的内容如下所示:
01&?xml version="1.0" encoding="UTF-8"?&02&03&beans xmlns=""04&&&&xmlns:xsi="" xmlns:dubbo=""05&&&&xsi:schemaLocation=" 06&&&&& "&07&08&&&&&dubbo:application name="search-provider" /&09&&&&&dubbo:registry10&&&&&&&&address=",slave4:2188" /&11&&&&&dubbo:protocol name="hessian" port="8080" server="servlet" /&12&&&&&bean id="searchService"13&&&&&&&&class="org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer"&14&&&&&&&&&property name="baseUrl" value="" /&15&&&&&/bean&16&&&&&dubbo:service17&&&&&&&&interface="org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService"18&&&&&&&&ref="searchService" path="http_dubbo/search" /&19&20&/beans&
因为使用Tomcat发布提供方服务,所以我们需要实现Spring的org.springframework.web.context.ContextLoader来初始化应用上下文(基于Spring的IoC容器来管理服务对象)。实现类SearchContextLoader代码如下所示:
01package org.shirdrn.platform.dubbo.02&03import javax.servlet.ServletContextE04import javax.servlet.ServletContextL05&06import org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchS07import org.springframework.context.support.ClassPathXmlApplicationC08import org.springframework.web.context.ContextL09&10public class SearchContextLoader extends ContextLoader implements ServletContextListener {11&12&&&&@Override13&&&&public void contextDestroyed(ServletContextEvent arg0) {14&&&&&&&&// TODO Auto-generated method stub15&16&&&&}17&18&&&&@Override19&&&&public void contextInitialized(ServletContextEvent arg0) {20&&&&&&&&String config = arg0.getServletContext().getInitParameter("contextConfigLocation");21&&&&&&&&ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(config);22&&&&&&&&context.start();23&&&&}24&25}
最后,配置Web应用部署描述符文件,web.xml内容如下所示:
01&?xml version="1.0" encoding="UTF-8"?&02&web-app id="WebApp_ID" version="2.4"03&&&&xmlns="" xmlns:xsi=""04&&&&xsi:schemaLocation=" "&05&&&&&display-name&http_dubbo&/display-name&06&07&&&&&listener&08&&&&&&&&&listener-class&org.shirdrn.platform.dubbo.context.SearchContextLoader&/listener-class&09&&&&&/listener&10&&&&&context-param&11&&&&&&&&&param-name&contextConfigLocation&/param-name&12&&&&&&&&&param-value&classpath:search-provider.xml&/param-value&13&&&&&/context-param&14&15&&&&&servlet&16&&&&&&&&&servlet-name&search&/servlet-name&17&&&&&&&&&servlet-class&com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet&/servlet-class&18&&&&&&&&&init-param&19&&&&&&&&&&&&&param-name&home-class&/param-name&20&&&&&&&&&&&&&param-value&org.shirdrn.platform.dubbo.service.rpc.server.SolrSearchServer&/param-value&21&&&&&&&&&/init-param&22&&&&&&&&&init-param&23&&&&&&&&&&&&&param-name&home-api&/param-name&24&&&&&&&&&&&&&param-value&org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService&/param-value&25&&&&&&&&&/init-param&26&&&&&&&&&load-on-startup&1&/load-on-startup&27&&&&&/servlet&28&&&&&servlet-mapping&29&&&&&&&&&servlet-name&search&/servlet-name&30&&&&&&&&&url-pattern&/search&/url-pattern&31&&&&&/servlet-mapping&32&33&&&&&welcome-file-list&34&&&&&&&&&welcome-file&index.html&/welcome-file&35&&&&&&&&&welcome-file&index.htm&/welcome-file&36&&&&&&&&&welcome-file&index.jsp&/welcome-file&37&&&&&&&&&welcome-file&default.html&/welcome-file&38&&&&&&&&&welcome-file&default.htm&/welcome-file&39&&&&&&&&&welcome-file&default.jsp&/welcome-file&40&&&&&/welcome-file-list&41&/web-app&
启动Tomcat以后,就可以将提供方服务发布到服务注册中心,这里服务注册中心我们使用的是ZooKeeper集群,可以参考上面Dubbo配置文件search-provider.xml的配置内容。
下面,我们通过两种方式来调用已经注册到服务注册中心的服务。
基于Dubbo的Hessian协议远程调用
服务消费方,通过Dubbo配置文件来指定注册到注册中心的服务,配置文件search-consumer.xml的内容,如下所示:
01&?xml version="1.0" encoding="UTF-8"?&02&03&beans xmlns=""04&&&&xmlns:xsi="" xmlns:dubbo=""05&&&&xsi:schemaLocation=" 06&&&&& "&07&08&&&&&dubbo:application name="search-consumer" /&09&&&&&dubbo:registry10&&&&&&&&address=",slave4:2188" /&11&&&&&dubbo:reference id="searchService"12&&&&&&&&interface="org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService" /&13&14&/beans&
然后,使用Java实现远程调用,实现代码如下所示:
01package org.shirdrn.platform.dubbo.service.rpc.02&03import java.util.concurrent.C04import java.util.concurrent.F05&06import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchS07import org.springframework.beans.BeansE08import org.springframework.context.support.AbstractXmlApplicationC09import org.springframework.context.support.ClassPathXmlApplicationC10&11import com.alibaba.dubbo.rpc.RpcC12&13public class SearchConsumer {14&15&&&&private final S16&&&&private AbstractXmlApplicationC17&&&&private SolrSearchService searchS18&19&&&&public SearchConsumer(String collection, Callable&AbstractXmlApplicationContext& call) {20&&&&&&&&super();21&&&&&&&&this.collection =22&&&&&&&&try {23&&&&&&&&&&&&context = call.call();24&&&&&&&&&&&&context.start();25&&&&&&&&&&&&searchService = (SolrSearchService) context.getBean("searchService");26&&&&&&&&} catch (BeansException e) {27&&&&&&&&&&&&e.printStackTrace();28&&&&&&&&} catch (Exception e) {29&&&&&&&&&&&&e.printStackTrace();30&&&&&&&&}31&&&&}32&33&&&&public Future&String& asyncCall(final String q, final String type, final int start, final int rows) {34&&&&&&&&Future&String& future = RpcContext.getContext().asyncCall(new Callable&String&() {35&&&&&&&&&&&&public String call() throws Exception {36&&&&&&&&&&&&&&&&return search(q, type, start, rows);37&&&&&&&&&&&&}38&&&&&&&&});39&&&&&&&&return 40&&&&}41&42&&&&public String syncCall(final String q, final String type, final int start, final int rows) {43&&&&&&&&return search(q, type, start, rows);44&&&&}45&46&&&&private String search(final String q, final String type, final int start, final int rows) {47&&&&&&&&return searchService.search(collection, q, type, start, rows);48&&&&}49&50&&&&public static void main(String[] args) throws Exception {51&&&&&&&&final String collection = "tinycollection";52&&&&&&&&final String beanXML = "search-consumer.xml";53&&&&&&&&final String config = SearchConsumer.class.getPackage().getName().replace('.', '/') + "/" + beanXML;54&&&&&&&&SearchConsumer consumer = new SearchConsumer(collection, new Callable&AbstractXmlApplicationContext&() {55&&&&&&&&&&&&public AbstractXmlApplicationContext call() throws Exception {56&&&&&&&&&&&&&&&&final AbstractXmlApplicationContext context = new ClassPathXmlApplicationContext(config);57&&&&&&&&&&&&&&&&return 58&&&&&&&&&&&&}59&&&&&&&&});60&61&&&&&&&&String q = "q=上海&fl=*&fq=building_type:1";62&&&&&&&&int start = 0;63&&&&&&&&int rows = 10;64&&&&&&&&String type = "xml";65&&&&&&&&for (int k = 0; k & 10; k++) {66&&&&&&&&&&&&for (int i = 0; i & 10; i++) {67&&&&&&&&&&&&&&&&start = 1 * 10 *68&&&&&&&&&&&&&&&&if (i % 2 == 0) {69&&&&&&&&&&&&&&&&&&&&type = "xml";70&&&&&&&&&&&&&&&&} else {71&&&&&&&&&&&&&&&&&&&&type = "json";72&&&&&&&&&&&&&&&&}73&&&&&&&&&&&&&&&&String result = consumer.syncCall(q, type, start, rows);74&&&&&&&&&&&&&&&&System.out.println(result);75&&&&&&&&&&&&&&&&// Future&String& future = consumer.asyncCall(q, type, start,76&&&&&&&&&&&&&&&&// rows);77&&&&&&&&&&&&&&&&// System.out.println(future.get());78&&&&&&&&&&&&}79&&&&&&&&}80&&&&}81&82}
执行该调用实现,可以远程调用提供方发布的服务。
这种方式限制了服务调用方也必须使用Dubbo来开发调用的代码,也就是限制了编程的语言,而无论是对于内部还是外部,各个团队之间必然存在语言的多样性,如果限制了编程语言,那么开发的服务也只能在内部使用。
基于标准Hessian协议接口的远程调用
下面,使用标准Hessian接口来实现远程调用,这时就不需要关心服务提供方的所使用的开发语言,因为最终是通过HTTP的方式来访问。我们需要下载Hessian对应语言的调用实现库,才能更方便地编程。
使用Java语言实现远程调用
使用Java语言实现,代码如下所示:
01package org.shirdrn.rpc.02&03import org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchS04&05import com.caucho.hessian.client.HessianProxyF06&07public class HessianConsumer {08&09&&&&public static void main(String[] args) throws Throwable {10&11&&&&&&&&String serviceUrl = "";12&&&&&&&&HessianProxyFactory factory = new HessianProxyFactory();13&14&&&&&&&&SolrSearchService searchService = (SolrSearchService) factory.create(SolrSearchService.class, serviceUrl);15&16&&&&&&&&String q = "q=上海&fl=*&fq=building_type:1";17&&&&&&&&String collection = "tinycollection";18&&&&&&&&int start = 0;19&&&&&&&&int rows = 10;20&&&&&&&&String type = "xml";21&&&&&&&&String result = searchService.search(collection, q, type, start, rows);22&&&&&&&&System.out.println(result);23&&&&}24}
我们只需要知道提供服务暴露的URL和服务接口即可,这里URL为,接口为org.shirdrn.platform.dubbo.service.rpc.api.SolrSearchService。运行上面程序,可以调用提供方发布的服务。
使用Python语言实现远程调用
使用Python客户端来进行远程调用,我们可以从下载,然后安装Hessian的代理客户端Python实现库:
1git clone 2cd mustaine3sudo python setup.py install
然后就可以使用了,使用Python进行远程调用的实现代码如下所示:
01#!/usr/bin/python02&03# coding=utf-804from mustaine.client import HessianProxy05&06serviceUrl = ''07q = 'q=*:*&fl=*&fq=building_type:1'08start = 009rows = 1010resType = 'xml'11collection = 'tinycollection'12&13if __name__ == '__main__':14&&&&&proxy = HessianProxy(serviceUrl)15&&&&&result = proxy.search(collection, q, resType, start, rows)16&&&&&print result
运行上面程序,就可以看到远程调用的结果。
本文基于许可协议发布,欢迎转载、使用、重新发布,但务必保留文章署名(包含链接),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我。
发表评论:
TA的最新馆藏Hessian和Java反序列化问题小结 - 笨小孩 - ITeye技术网站
博客分类:
Hessian反序列化问题
众所周知,Hessian框架提供的序列化方式,在性能上要优于Java自己的序列化方式。他将对象序列化,生成的字节数组的数量要相对于Java自带的序列化方式要更简洁。
目前公司的一个项目中,有RPC调用的需要,这里我们使用了公司自己的开源RPC框架Dubbo作为远程调用框架,进行业务方法的调用和对象的序列化。这里,我们没有对Dubbo做出特殊配置,Dubbo在Remoting层组件默认的序列化方式就是采用的Hessian协议处理。但是在真正部署测试时,走到需要远程调用的方式时,报出了一下异常(只截取了最核心的异常堆栈):
Caused by: .caucho.hessian.io.HessianProtocolException: 'com.alibaba.ais.bdc.person.vo.CountVO$CountObject' could not be instantiated
at .caucho.hessian.io.JavaDeserializer.instantiate(JavaDeserializer.java:275)
at .caucho.hessian.io.JavaDeserializer.readObject(JavaDeserializer.java:155)
at .caucho.hessian.io.SerializerFactory.readObject(SerializerFactory.java:397)
at .caucho.hessian.io.Hessian2Input.readObjectInstance(Hessian2Input.java:2070)
at .caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:2005)
at .caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1990)
at .caucho.hessian.io.CollectionDeserializer.readLengthList(CollectionDeserializer.java:93)
at .caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1678)
at .caucho.hessian.io.JavaDeserializer$ObjectFieldDeserializer.deserialize(JavaDeserializer.java:396)
... 42 more
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at .caucho.hessian.io.JavaDeserializer.instantiate(JavaDeserializer.java:271)
... 50 more
Caused by: java.lang.IllegalArgumentException: [Assertion failed] - this
it must not be null
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.util.Assert.notNull(Assert.java:123)
at com.alibaba.ais.bdc.person.vo.CountVO$CountObject.&init&(CountVO.java:101)
... 55 more
从最下面的异常信息可以看出,CountObject这个内部类在对象初始化时,报了参数校验的失败。这个看一下CountObject的出问题的构造函数就一目了然了:
public CountObject(SimplePerson simplePerson, String imagePrefix){
Assert.notNull(simplePerson);
if (StringUtils.isEmpty(imagePrefix)) {
throw new IllegalArgumentException("imagePrefix [" + imagePrefix + "] is meaningless.");
this.id = simplePerson.getEmployeeId();
this.name = simplePerson.getRealName();
this.imagePath = StringUtils.isEmpty(simplePerson.getImagePathSuffix()) ? null : imagePrefix
+ simplePerson.getImagePathSuffix();
现在在构造函数的第一行的Assert就失败了。可是哪里调用这个构造函数导致失败呢?继续网上翻看异常堆栈给出的信息。可以看出在JavaDeserializer.instantiate中抛出了HessianProtocolException异常。进去看一下Hessian这块的源码如下:
protected Object instantiate()
throws Exception
if (_constructor != null)
return _constructor.newInstance(_constructorArgs);
return _type.newInstance();
} catch (Exception e) {
throw new HessianProtocolException("'" + _type.getName() + "' could not be instantiated", e);
这里结合上面的异常堆栈可以知道,上面出问题的关键是_constructor和_constructorArgs。这两个东东又到底是啥呢?继续来看代码:
public JavaDeserializer(Class cl)
_fieldMap = getFieldMap(cl);
_readResolve = getReadResolve(cl);
if (_readResolve != null) {
_readResolve.setAccessible(true);
Constructor []constructors = cl.getDeclaredConstructors();
long bestCost = Long.MAX_VALUE;
for (int i = 0; i & constructors. i++) {
Class []param = constructors[i].getParameterTypes();
long cost = 0;
for (int j = 0; j & param. j++) {
cost = 4 *
if (Object.class.equals(param[j]))
cost += 1;
else if (String.class.equals(param[j]))
cost += 2;
else if (int.class.equals(param[j]))
cost += 3;
else if (long.class.equals(param[j]))
cost += 4;
else if (param[j].isPrimitive())
cost += 5;
cost += 6;
if (cost & 0 || cost & (1 && 48))
cost = 1 && 48;
cost += (long) param.length && 48;
// _constructor will reference to the constructor with least parameters.
if (cost & bestCost) {
_constructor = constructors[i];
bestCost =
if (_constructor != null) {
_constructor.setAccessible(true);
Class []params = _constructor.getParameterTypes();
_constructorArgs = new Object[params.length];
for (int i = 0; i & params. i++) {
_constructorArgs[i] = getParamArg(params[i]);
从JavaDeserializer的构造方法中可以看出,这里_constructor会被赋予参数最少的那个构造器。再回过头去看看CountObject的构造器(就上面列出来的那一个),不难看出,这里的_constructor就是上面的那个构造器了。
* Creates a map of the classes fields.
protected static Object getParamArg(Class cl)
if (! cl.isPrimitive())
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);
throw new UnsupportedOperationException();
参看上面的getParamArg方法,就可以知道,由于CountObject唯一的一个构造器的两个参数都不是基本类型,所以这里_constructorArgs所包含的值全部是null。
OK,到这里,上面的异常就搞清楚了,Hessian反序列化时,使用反射调用构造函数生成对象时,传入的参数不合法,造成了上面的异常。知道了原因,解决的方法也很简单,就是添加了一个无参的构造器给CountObject,于是上面的问题就解决了。。。
这里,需要注意的是,如果序列化机制使用的是Hessian,序列化的对象又没有提供默认的无参构造器时,需要注意上面类似的问题了。
Java本身反序列化问题
Java本身的反序列化机制虽然性能稍差一些,但本身使用的约束条件相对却要宽松一些,其实只要满足下面两条,一个类对象就是可以完美支持序列化机制了:
类实现java.io.Serializable接口。
类包含的所有属性都是实现了java.io.Serializable接口的,或者被标记为了transient。
对于构造函数本身没有任何约束。这里,Java序列化本身其实也是和new以及Java反射机制“平级”的实例化对象的方式。所以,对于单例模式的场景,还是需要考虑是否会有序列化因素造成的单例失效(因为他实例化对象不依赖于构造器,所以一个private的构造器显然没法阻止他的“胡作非为”)。当然,对于这种情况,也可以自己实现下面的方法:
private Object readResolve()
通过实现上面的方法,自己可以在其中明确指定,放回的对象的实例是哪一个。但对于通过如上方式保证的单例模式至少需要注意一下两点:
readResolve方法的可见性(public/protected/private)问题:因为如果这个方法不是private的,就有可能被起子类直接继承过去。这可能造成你在反序列化子类对象时出错(因为这个方法返回了父类的某个固定的对象)。
使用readResolve方法时,往往比较容易返回某个固定的对象。但这其实和真正的对象反序列化其实是有点矛盾的。因为你反序列化对象时,多数场景都是希望恢复原来的对象的“状态”,而不是固定的某个对象。所以只要你的类内的属性有没有被标识成transient的,就要格外小心了。
鉴于上面所说的稍微复杂的现象,如果单纯的考虑单例的需要,更好的方式是通过枚举来实现,因为枚举至少可以在JVM层面,帮你保证每个枚举实例一定是单例的,即使使用反序列化机制,也无法绕过这个限制,所以可以帮你省不少心。
好了,上面扯的有点远了,关于Java本身的序列化机制,下面写了一个简单的把对象序列化成字节数组,再由字节数组反序列化回来的例子,看完之后应该会更明了一些:
public class Person implements Serializable {
public Person(String name, int age) {
this.name =
this.age =
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
private static class Employee extends Person{
private Employee(String name, int age, String title) {
super(name, age);
this.title =
public String toString() {
return "Employee{" + "name='" + name + '\'' +
", age=" + age + '\'' +
", title='" + title + '\'' +
public static void main(String[] args) {
Person person1 = new Person( "test1",20 );
Person person2;
Employee employee1 = new Employee( "employee1",25,"Manager" );
Employee employee2;
ByteArrayOutputStream byteOutputStream =
ObjectOutputStream objectOutputStream =
ByteArrayInputStream byteArrayInputStream =
ObjectInputStream objectInputStream =
//generate byteArray.
byteOutputStream = new ByteArrayOutputStream( );
objectOutputStream = new ObjectOutputStream( byteOutputStream);
//serialize person1
objectOutputStream.writeObject( person1 );
//serialize employee1
objectOutputStream.writeObject( employee1 );
bytes = byteOutputStream.toByteArray();
for (byte aByte : bytes) {
System.out.print(aByte);
System.out.println();
System.out.println("Bytes's length is :"+bytes.length);
//generate Object from byteArray.
byteArrayInputStream = new ByteArrayInputStream( bytes );
objectInputStream = new ObjectInputStream( byteArrayInputStream );
//deserialize person1
person2 = (Person)objectInputStream.readObject();
//deserialize employee1
employee2 = (Employee)objectInputStream.readObject();
System.out.println("person2 got from byteArray is : "+person2);
System.out.println("employee2 got from byteArray is : "+employee2);
System.out.println("person1's memory id :"+Integer.toHexString(person1.hashCode()));
System.out.println("person2's memory id :"+Integer.toHexString(person2.hashCode()));
System.out.println("employee1's memory id :"+Integer.toHexString(employee1.hashCode()));
System.out.println("employee2's memory id :"+Integer.toHexString(employee2.hashCode()));
} catch (IOException e) {
e.printStackTrace();
}catch ( ClassNotFoundException ce ){
ce.printStackTrace();
byteOutputStream.close();
objectOutputStream.close();
byteArrayInputStream.close();
objectInputStream.close();
} catch (IOException e) {
e.printStackTrace();
上面代码执行的结果如下:
-84--26-11----14
Bytes's length is :200
person2 got from byteArray is : Person{name='test1', age=20}
employee2 got from byteArray is : Employee{name='employee1', age=25', title='Manager'}
person1's memory id :29173ef
person2's memory id :96fa474
employee1's memory id :6c121f1d
employee2's memory id :95c083
最后再补充一个Java序列化规范的地址,有时间时再细读一下:
浏览 16666
浏览: 264919 次
来自: 杭州
解决了我的问题, 3q
grep也可以换成sed:find . -name &quot ...
好仔细的文,正愁这问题。很好的解释。
读君一博,解我一周愁
你好,能问下你的查看SQL执行顺序的工具是什么工具。

我要回帖

更多关于 dubbo proxy hessian 的文章

 

随机推荐