http://www.google.com.hk/gwt/x?oe=UTF-8&gl=CN&q=java+%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8&hl=zh_CN&ei=o7_1TLCTHsm5kgWbjIDSAQ&ved=0CAoQFjAB&source=m&rd=1&u=http://blog.sina.com.cn/s/blog_4b6047bc010008q7.html
序列化对象在Java中主要有两个目的,一个是钝化存储对象,另一个是通过网络传输对象。后者是移动或者远程计算的基础。前者比较好办,对象存储之后,往往由同一个程序再读出,对象在解析的时候不存在类加载的问题。后者比较麻烦,接收序列化对象的一端往往同发送端的类加载器环境不一样,很有可能找不到发送端才有的类代码,因此也就无法反序列化对象,造成ClassNotFoundException。
Java中利用序列化机制进行移动/远程计算的一个机制是RMI。RMI客户端通过网络通信将序列化的参数对象传送给服务器端,服务器端将客户端传送来得的参数反序列化之后,调用相应对象的方法,并将结果序列化之后传送给客户端,客户端收到序列化的结果后,再使用反序列化功能将结果对象还原返回给调用程序。这是一般远程过程调用的基本原理,只是不同的远程过程调用采用的序列化和反序列化的方法不一样,更一般的远程过程调用系统比如Web服务(如SOAP协议)或者Corba协议,则采用XML或者定义中间数据类型的模式,客户端和服务器端将调用参数和返回结果采用XML或者中间语言表达的方法实现类型系统的转化。
不像一般远程过程调用系统需要你自定义数据类型转化过程,Java的序列化机制将类描述和反射机制结合起来,实现了自动序列化的过程,降低了开发难度和复杂度。为了能序列化和反序列化,序列化的双方必须知道(懂得)序列化的类的结构,这就是为甚么要在序列化和反序列化过程使用类加载器来加载所需的类。序列化流中保存了类的表述信息,比如类的名称,类的签名等,反序列化的一方在读取这些信息之后,就需要根据这些信息加载该类,以便通过反射生成对象,并将后续的对象数据读取进来。
那么反序列化的一方如何加载对方的类呢?缺省的ObjectInputStream类获取调用栈上最近用户自定义的类加载器,如果没有用户自定义的类加载器,则使用当前线程的ContextClassLoader。一般来说这个ContextClassLoader就是应用程序的BootstrapClassLoader,它包括了JRE和应用程序的类路径。然而服务器方的类路经一般不可能覆盖客户端的类路径,这时就需要替换这个类加载器,让它按照自定义的地方找类代码。
RMI替换了这个类加载器,它自定义的类加载器可以从指定的URL下载特定的类代码,并根据需要加载这个类,从而完成反序列化过程。所以熟悉RMI的朋友就会发现为了实现一个RMI调用,过程是非常复杂的,你不仅要指定服务器端供应类代码的URL,还要指定客户端供应类代码的URL,毕竟服务器端和客户端都不仅仅需要序列化,也需要反序列化,才能完成对象交换。代码从另一个位置,典型的是网络上,传输另一个地方被解析执行,这就是通常移动计算的来历。由于代码是传自另一个位置,又会设计到执行移动代码的安全问题。幸亏Java的安全系统设计的非常完美,它的模型完美的解决了移动计算的问题。
我最近帮朋友做的这个平台,一个基本机制就是远程过程调用。没有采用RMI机制,原因是RMI机制太过底层,对于一般Java程序员来说完成一个调用过程非常痛苦。也没有采用封装RMI的形式,因为RMI的基本模型即接口和实现未免太过复杂,对于程序员要求还是过高。我们的原型是普通一个Java业务类,通过自己写的动态代理封装出客户端和服务器端来。前面有篇文章:Java动态代理、ASM与AOP就是描述这个机制的。这样带来的开发模式时,程序员按照桌面应用的模式开发软件,可以不用修改地部署到客户端/服务器端的这种模式上,将复杂的企业应用的开发和部署变成了简单的桌面软件的开发。
当然在写这个平台时候,我就遇到这个困惑,如何将应用程序的运行空间同平台的运行空间分离开,如何将A程序的运行空间同B程序的运行空间分离开?开始由于这个问题没有搞清楚,结果使用了缺省的ObjectInputStrea类,使得平台进行序列化和反序列化过程中老是使用平台的类加载器,当要序列化和反序列化应用程序的类对象时,n多的ClassNotFoundException就出来了。
可能我的脑筋当时就是转不过来了,死活没有想到用自定义的ObjectInputStream来取代JDK的ObjectInputStream,就是在琢磨如何将ObjectInputStream的调用栈的类加载器替换成自己的。后来想清楚了,在使用自定义的ObjectInputStream的情况是不可能的。今天天气不错,我喝了杯回到座位上时,突然想起来为什么不自己写ObjectInputStream呢,自己来控制序列化的过程,起码是部分控制就已经足够,这样不就可以替换自己的了吗?^_^
有了这个想法,实现就很容易了。我赶紧打开JDK的src.zip,研究ObjectInputStream,看哪些方法是可以覆盖来改变行为的。结果是,其实这个问题很简单,只是我太固执。人家已经明明白白的写好了如果你继承这个方法会怎么怎么样改变行为,还有例子。
人要是固执起来,真是不可理喻。我差点没有撞到南墙上,总算还想起来可以绕过南墙过去。
如何解决,很简单,覆盖ObjectInputStream中的resolveClass方法。这个方法就是在反序列化过程中读取类描述后加载类而使用的。这儿你只要给它返回它的描述需要的类就行了,至于你怎么加载,全部在你的控制之下。
看了这个东西,顺便看了一下这个方法对应的ObjectOutputStream方法是annotateClass,它的意思是在序列化改类时如何描述改类。缺省的实现是空。你可以覆盖它,加上你自己的东西,比如干脆将类代码放在这儿,防止对方找不到类。在ObjectInputStream的自定义类中,你就可以将这个写类代码解析了使用。代码随着对象一起传输,再一次形象表述了所谓移动计算。
今天将这个思想转变记录下来,算是做一个笔记。如果你也有在这儿也有犯糊涂绕不过这个弯的,不妨提醒一下,绕过去。
分享到:
相关推荐
- Protocol Buffer:由于PB的数据格式是自定义的,不像Java序列化那样容易受到反序列化攻击,因此在安全性方面更胜一筹。 - Java序列化:Java序列化可能存在安全风险,比如恶意构造的序列化数据可能导致远程代码...
- Java允许使用 `writeObject()` 和 `readObject()` 方法来自定义序列化和反序列化的行为,这两个方法需要在类中声明为`private`,并由`java.io.Serializable` 接口的实现类提供。 7. **序列化安全性** - 序列化...
综上所述,要理解并实现Android中Parcelable序列化自定义类集合在Activity间传递,开发者需要掌握Parcelable接口的使用、自定义类的Parcelable实现、集合处理、Intent数据传递,以及可能借助的源码阅读和辅助工具。...
2. **定义反序列化器类**:创建一个名为MyDeserializerFunc的类,并使其实现DebeziumDeserializationSchema接口。这个类将封装自定义的反序列化逻辑。 3. **实现deserialize方法**:在这个方法中,我们将处理从...
通过使用`transient`关键字、自定义序列化方法或第三方库,我们可以排除对象中不希望被序列化的属性。理解这些机制对于编写安全且高效的Java应用程序至关重要。 在学习过程中,阅读相关的文档和博客,例如提供的...
例如,我们可以编写一个自定义的反序列化器来处理JSON字符串中的日期格式,使其能够正确地映射到Java的Date或LocalDate对象上。 总结来说,理解并掌握ObjectMapper的readValue方法是进行JSON反序列化工作的基础。...
2. **注册序列化器**:如果需要序列化的类没有实现`Serializable`接口,可以使用FST的注册机制,指定自定义的序列化和反序列化逻辑。 3. **序列化操作**:使用`FSTObjectOutput`进行序列化,`FSTObjectInput`进行反...
在Java中,如果一个类需要支持序列化,它应该实现`java.io.Serializable`接口。 在Java序列化过程中,`serialVersionUID`扮演着至关重要的角色。`serialVersionUID`是一个长期不变的标识符,用于验证序列化版本的...
在Java中,一个类如果要实现序列化,需要实现`Serializable`接口,这是一个标记接口,不包含任何方法。下面我们将详细讨论Java序列化的用途、注意事项以及如何实现。 1. **序列化用途**: - **持久化存储**:将...
在Java环境中,Protobuf-java库提供了编译器工具,可以将.proto文件编译为Java类,这些类包含序列化和反序列化的方法。Protobuf特别适用于跨平台的通信,如服务器与客户端之间的数据交换,或者作为数据库的存储格式...
为了实现 Java 序列化,需要将需要被序列化的类实现 Serializable 接口,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,接着,使用 ObjectOutputStream 对象的 ...
Java的序列化机制允许开发者在类中定义`readObject()`和`writeObject()`方法来自定义序列化和反序列化的行为,或者使用`transient`关键字来排除某些字段不参与序列化。 总之,Java序列化是一个强大的工具,它使得...
### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的状态转换成字节流的过程,以便于在网络上传输或存储到磁盘上。Java序列化标准定义了一套规则来描述如何...
下面我们将详细讨论Java的类加载过程以及如何利用自定义类加载器实现反序列化。 1. **类加载流程**: - 当需要加载一个类时,通常会调用`ClassLoader`的`loadClass`公共方法。这个方法进一步调用`loadClass`的保护...
为了避免循环引用导致的无限递归,Java序列化机制采用了一种称为“写替换”(writeReplace)的技术,允许用户自定义序列化的过程,以满足特定的业务需求或性能优化。 总之,Java序列化不仅仅是一种简单的对象持久化...
序列化过程中,涉及到的对象可能需要通过类加载器动态加载。Java的类加载机制确保了同一个类只会被同一个类加载器加载一次。这对于序列化来说非常重要,因为反序列化过程需要确保使用的类版本与序列化时一致。 ####...
1. `java.io.ObjectOutputStream`和`java.io.ObjectInputStream`:基础的序列化和反序列化工具类。 2. `java.io.Serializable`: 标记接口,表明对象支持序列化。 3. `java.io.NotSerializableException`: 当尝试序列...
然后,在创建Gson实例时,通过`GsonBuilder`添加自定义序列化器: ```java Gson gson = new GsonBuilder() .registerTypeAdapter(Date.class, new CustomDateSerializer()) .create(); ``` ### Gson自定义反序列...
在Java中,`java.io.Serializable`接口用于标记那些可以被序列化的类。下面将详细介绍Java文件序列化读写的相关知识点。 1. **序列化的目的**: - **持久化对象**:将对象状态保存到文件或数据库中,即使程序关闭...
综上所述,Netty服务端和客户端利用Java序列化传输数据涉及到Java序列化基础、Netty的ByteBuf、ChannelHandlerContext、自定义编码解码器、安全性和性能优化等多个知识点。在实际应用中,需要结合具体业务需求进行...