java反序列化时的类加载

简介: 序列化对象在Java中 主要有两个目的,一个是钝化存储对象,另一个是通过网络传输对象。 后者是移动或者远程计算的基础。前者比较好办,对象存储之后,往往由同一个程序再读出, 对象在解析的时候不存在类加载的问题。

序列化对象在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的自定义类 中,你就可以将这个写类代码解析了使用。代码随着对象一起传输,再一次形象表述了所谓移动计算。


原文链接:http://blog.csdn.net/xiemk2005/article/details/5850449

目录
相关文章
|
23天前
|
存储 安全 Java
🌟Java零基础-反序列化:从入门到精通
【10月更文挑战第21天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
63 5
|
24天前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
24 3
|
27天前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
1月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
1月前
|
分布式计算 资源调度 Hadoop
Hadoop-10-HDFS集群 Java实现MapReduce WordCount计算 Hadoop序列化 编写Mapper和Reducer和Driver 附带POM 详细代码 图文等内容
Hadoop-10-HDFS集群 Java实现MapReduce WordCount计算 Hadoop序列化 编写Mapper和Reducer和Driver 附带POM 详细代码 图文等内容
98 3
|
1月前
|
Java 数据库 对象存储
Java 序列化详解
本文详细解析了Java序列化的概念与应用。通过具体实例,深入探讨了其在对象存储和传输中的作用及实现方法,帮助读者理解如何有效利用这一特性来简化数据交换,并对其实现机制有了更深入的认识。
|
1月前
|
安全 网络协议 Java
Java反序列化漏洞与URLDNS利用链分析
Java反序列化漏洞与URLDNS利用链分析
51 3
|
26天前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
26 0
|
2月前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
115 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
下一篇
无影云桌面