JDK序列化机制及源码解读三:ObjectInputStream对象输入流
这是Java序列化机制及源码解读系列的第三篇,主要学习JDK处理对象输入流的方法。有了ObjectOutputStream的分析,ObjectInputStream解读起来更得心应手,所以这里我们仅分析下ObjectInputStream的构造方法和readObject方法。
1、ObjectInputStream的构造方法
1 | public ObjectInputStream(InputStream in) throws IOException { |
BlockDataInputStream跟 BlockDataOutputStream类似,不过是反过来,其作用是从输入流读取byte数据,read[Type]和read[Type]s将byte转为Java基元数据,并且会返回对应类型的对象。
2、readObject
readObject
两种情况读取对象,一种类重写了readObject,直接调用重写方法,否则调用readObject0反序列化。
1 | public final Object readObject() |
readObject0
1 | private Object readObject0(boolean unshared) throws IOException { |
read[String|Array|Enum]
读取实例值并返回对应对象
1 | //String的读取,并返回字符串对象 |
readOrdinaryObject:
readOrdinaryObject主要4个步骤:
- 根据TC_OBJECT判断是否是对象;
- 调用readClassDesc读取类元信息,用来创建实例;
- 调用Externalize/Serializable获取对象属性域信息并赋值给对象的属性;
- 如果是实现了readResolve,调用readResolve来直接替换前面第2-3步反序列化的对象。
1 | private Object readOrdinaryObject(boolean unshared) |
ObjectStreamClass#readClassDesc和readNonProxy:读取类元信息
步骤:
- 获取类的类名;
- 获取类的serialVersionUID;
- 获取类使用的序列化方式;
- 获取类所有序列化的属性
这些信息将会被封装在ObjectStreamClass返回。
1 | private ObjectStreamClass readClassDesc(boolean unshared) |
readExternalData/readSerialData获取对象属性域信息:
readSerialData未重写readObject会调用默认处理方法defaultReadFields
1 | private void readSerialData(Object obj, ObjectStreamClass desc) throws IOException { |
defaultReadFields:属性值具体操作
- 获取所有原生类型的属性数据并赋值对象属性:调用ObjectStreamClass#setPrimFieldValues给所有属性进行赋值
- 获取所有非原生类型的属性数据并赋值:循环读取每个非原生属性,用readObject0递归调用
1 | private void defaultReadFields(Object obj, ObjectStreamClass desc) throws IOException { |
3、总结-对象输入流规则
跟对象输出规则一致,也是按照三部分进行,其实每部分也都一样的,不过一个是写入,一个是读取罢了。
ObjectInputStream读取规则如下:
- 第一部分获取序列化头信息:描述序列化协议的信息和版本;
- 第二部分获取类元信息包括序列化的类名称、以及哪些属性是被序列化的,获取到后用newInstance构造一个类的对象。
- 第三部分获取属性域的值信息,赋值对应序列化的每个属性。
更新-拓展:
weblogic经常打补丁的地方:resolveClass。
1、原生ObjectInputStream.resolveClass很简单,就是获取类名。
1 | protected Class<?> resolveClass(ObjectStreamClass desc) |
在readNonProxyDesc中进行了调用
在readClassDesc中,当TC是一个类描述符,调用readNonProxyDesc获取类名。
2、Weblogic的weblogic.rjvm.InboundMsgAbbrev
中,对类进行了黑名单检测
1 | protected Class resolveClass(ObjectStreamClass descriptor) throws ClassNotFoundException, IOException { |