Java-ObjectOutputStream 序列化 源码解析
注意序列化的实现有2中方式,一个是实现Serializable接口,另一个是实现Externalizable接口。
ObjectOutputStream
属性:
private int depth; //深度计数
构造方法:
public ObjectOutputStream(OutputStream out) throws IOException {
//验证这个对象是否是 ObjectOutputStream
verifySubclass();
//new 一个BlockDataOutputStream 对象
bout = new BlockDataOutputStream(out);
handles = new HandleTable(10, (float) 3.00);
subs = new ReplaceTable(10, (float) 3.00);
//允许 重写设为false
enableOverride = false;
writeStreamHeader();
bout.setBlockDataMode(true);//bkm= true old = false
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}
方法:
//验证这个对象是否是 ObjectOutputStream
private void verifySubclass() {
//获取对象的类 class 验证是否为ObjectOutputStream
Class<?> cl = getClass();
if (cl == ObjectOutputStream.class) {
return;
}
SecurityManager sm = System.getSecurityManager();
if (sm == null) {
return;
}
processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
Boolean result = Caches.subclassAudits.get(key);
if (result == null) {
result = Boolean.valueOf(auditSubclass(cl));
Caches.subclassAudits.putIfAbsent(key, result);
}
if (result.booleanValue()) {
return;
}
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
//序列化 开始写头部
protected void writeStreamHeader() throws IOException {
//STREAM_MAGIC 写序列化的魔数
//STREAM_VERSION 写序列化的版本号 这里只是写到 bout的 buf里面
bout.writeShort(STREAM_MAGIC);
bout.writeShort(STREAM_VERSION);
}
//外部调用 序列化的 入口
public final void writeObject(Object obj) throws IOException {
//如果没有自己继承ObjectOutputStream重写序列化,则enableOverride 一直是flase
if (enableOverride) {
writeObjectOverride(obj);
return;
}
try {//方法转移
writeObject0(obj, false);
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}
//写数据 unshared 为 false
private void writeObject0(Object obj, boolean unshared)
throws IOException
{//设置 blkmode,这个操作会触发 drain操作
//还是不会 触发writeBlockHeader 因为pos=0,这个drain方法判断pos==0的时候会 return
//oldMode = true
boolean oldMode = bout.setBlockDataMode(false);//bkm= false old = true
depth++;//层次深度
try {
// handle previously written and non-replaceable objects
int h;
//这里会直接返回其本身
if ((obj = subs.lookup(obj)) == null) {
writeNull();
return;
//这里的h=-1
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
//也不是
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
//也不是
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
// check for replacement object
Object orig = obj;
Class<?> cl = obj.getClass();//对象的class
ObjectStreamClass desc; //获取一些 字段的元信息
for (;;) {
// REMIND: skip this check for strings/arrays?
Class<?> repCl;
//这个会返回 传入这个class的ObjectStreamClass的对象,这个ObjectStreamClass的对象 里面会解析 cl 的 classname,属性 和方法 帮助完成 obj的 Class的元数据 和 数据 的序列化
desc = ObjectStreamClass.lookup(cl, true);
//desc.hasWriteReplaceMethod() 这个一般是false,所以这里直接break
if (!desc.hasWriteReplaceMethod() ||
(obj = desc.invokeWriteReplace(obj)) == null ||
(repCl = obj.getClass()) == cl)
{
break;
}
cl = repCl;
}
if (enableReplace) {//false
Object rep = replaceObject(obj);
if (rep != obj && rep != null) {
cl = rep.getClass();
desc = ObjectStreamClass.lookup(cl, true);
}
obj = rep;
}
// if object replaced, run through original checks a second time
if (obj != orig) {//no
subs.assign(orig, obj);
if (obj == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
}
//判断序列化对象的类型,安装类别写数据
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
writeEnum((Enum<?>) obj, desc, unshared);
} else if (obj instanceof Serializable) {//一般走这个判断
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode); //设置 setBlockDataMode 为 true
//这里会触发一次drain ,但不会写 header
}
}
//写objec 数据
private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
if (extendedDebugInfo) {
debugInfoStack.push(
(depth == 1 ? "root " : "") + "object (class \"" +
obj.getClass().getName() + "\", " + obj.toString() + ")");
}
try {
desc.checkSerialize();
bout.writeByte(TC_OBJECT);//写 这是个类 的标志
writeClassDesc(desc, false);//写 类的desc信息
handles.assign(unshared ? null : obj);//这里的目的是 当序列化多个对象的时候,当不共享 的时候,防止各个值冲突
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {//一般走这个分支,开始写真实的数据
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
//写类的描述信息
private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
int handle;
if (desc == null) {
writeNull();
} else if (!unshared && (handle = handles.lookup(desc)) != -1) {
writeHandle(handle);
} else if (desc.isProxy()) {
writeProxyDesc(desc, unshared);
} else {//一般走这个分支
writeNonProxyDesc(desc, unshared);
}
}
//写类的描述信息
private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_CLASSDESC);//写 这是个类描述标志 信息
handles.assign(unshared ? null : desc);
if (protocol == PROTOCOL_VERSION_1) {//not run this
// do not invoke class descriptor write hook with old protocol
desc.writeNonProxy(this);
} else {//使用 ObjectStreamClass 的方法写 类描述信息
writeClassDescriptor(desc);
}
//拿到待序列化的类的class类
Class<?> cl = desc.forClass();
bout.setBlockDataMode(true);//bkm= true old = true
if (cl != null && isCustomSubclass()) {//not
ReflectUtil.checkPackageAccess(cl);
}
annotateClass(cl);
bout.setBlockDataMode(false);//bkm= false old = true pos !=0 这里会写 blk header 写 buf中的内容 pos 置0 buf 里面都是 这个类的元信息
bout.writeByte(TC_ENDBLOCKDATA);//写block end 标志
// 这个类的元信息 写完成
writeClassDesc(desc.getSuperDesc(), false);//如果这个类有父类的话,还要写这个类的父类的class类的描述信息。(会重启一个 block 写新的类信息)一直到达顶级的父类//没有的话会写NULL flag标志
}
//使用 ObjectStreamClass 的方法写 类描述信息
protected void writeClassDescriptor(ObjectStreamClass desc)
throws IOException
{
desc.writeNonProxy(this);
//写的信息包括 全类名称,sid,flag标志(
//是否是serializable的实现,externalizable实现,flag 是SC_WRITE_METHOD,SC_SERIALIZABLE,SC_EXTERNALIZABLE,SC_BLOCK_DATA,SC_ENUM 的相与的结果)
//,字段数量,依次的每个字段的类型,名称,如果这个字段不是java基本类型需要写type signature
//注意这里并没有 写这个 类的其他信息。
}
//真正写object data 的入口
private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{//获取 obj对应的class 和其父类的 文件布局 ,
//这里的遍历是从 父类-》子类 的顺序开始 写的
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
//slots就是 他自己和父类的集合
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slotDesc.hasWriteObjectMethod()) {
PutFieldImpl oldPut = curPut;
curPut = null;
SerialCallbackContext oldContext = curContext;
if (extendedDebugInfo) {
debugInfoStack.push(
"custom writeObject data (class \"" +
slotDesc.getName() + "\")");
}
try {
curContext = new SerialCallbackContext(obj, slotDesc);
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
curContext.setUsed();
curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
curPut = oldPut;
} else {//默认一般走的是这个
defaultWriteFields(obj, slotDesc);
}
}
}
//写 obj value
private void defaultWriteFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
desc.checkDefaultSerialize();
//获取 class 基本属性数量 primVals 临时存放在这个byte数组
int primDataSize = desc.getPrimDataSize();
if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
}//unsafe直接获取class对象在内存偏移量的值,赋值给 primVals
desc.getPrimFieldValues(obj, primVals);
bout.write(primVals, 0, primDataSize, false); //写到输出流
ObjectStreamField[] fields = desc.getFields(false);
获取 class 非基本属性数量
Object[] objVals = new Object[desc.getNumObjFields()];
int numPrimFields = fields.length - objVals.length;
desc.getObjFieldValues(obj, objVals);
for (int i = 0; i < objVals.length; i++) {
if (extendedDebugInfo) {
debugInfoStack.push(
"field (class \"" + desc.getName() + "\", name: \"" +
fields[numPrimFields + i].getName() + "\", type: \"" +
fields[numPrimFields + i].getType() + "\")");
}
try {
//写 class 非基本属性数量 的 类信息 等 blk 信息,和 字段值
writeObject0(objVals[i],
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}
BlockDataOutputStream
ObjectOutputStream 中的内部类。
这个类的构造方法里面要传入一个参数OutputStream out的输入流实现类对象。
属性:
//最大的 blockSize 大小
private static final int MAX_BLOCK_SIZE = 1024;
//当前写buffer数据的偏移位置
private int pos = 0;
//暂时存放数据到 这个buf,待这个buf满了之后再一起写
private final byte[] buf = new byte[MAX_BLOCK_SIZE];
//block data mode
private boolean blkmode = false;
方法:
//设置 block data mode ,默认false, 当传进来 是 true的时候
//当 新的mode 与 就的mode相反时,则会触发drain操作,设置新的mode,返回旧的mode
boolean setBlockDataMode(boolean mode) throws IOException {
if (blkmode == mode) {
return blkmode;
}
drain();
blkmode = mode;
//这里 再调用drain,则会写 block header
return !blkmode;
}
//判断是否为 blkmode,是的话 写block header
//blkmode在false变为true,的下一次触发drain 的时候才会 writeBlockHeader,即在false-》true-》false时会触发 writeBlockHeader
//再写把buf的值一次写到 流中去,并且清空buf
void drain() throws IOException {
if (pos == 0) {
return;
}
if (blkmode) {
writeBlockHeader(pos);
}
out.write(buf, 0, pos);
pos = 0;
}
//写short类型
public void writeShort(int v) throws IOException {
if (pos + 2 <= MAX_BLOCK_SIZE) {
//暂时存放数据到 这个buf
Bits.putShort(buf, pos, (short) v);
pos += 2;
} else {
dout.writeShort(v);
}
}
//写 blockHeader
private void writeBlockHeader(int len) throws IOException {
//偏移数 不大于 256那么它就是2个byte的header
//否则是 5个byte的header
if (len <= 0xFF) {
hbuf[0] = TC_BLOCKDATA;
hbuf[1] = (byte) len;
out.write(hbuf, 0, 2);
} else {
hbuf[0] = TC_BLOCKDATALONG;
Bits.putInt(hbuf, 1, len);
out.write(hbuf, 0, 5);
}
}
DataOutputStream
构造方法:
//OutputStream out是 ObjectOutputStream的 输出流
public DataOutputStream(OutputStream out) {
super(out);
}
属性:
//统计 写入的 次数,即写入了 多少个 bit,8个bit加1 (一个Byte),和数据类型有关,int +1
protected int written;
private byte[] bytearr = null;
方法:
//写short类型,拆成高低位写
public final void writeShort(int v) throws IOException {
out.write((v >>> 8) & 0xFF);
out.write((v >>> 0) & 0xFF);
incCount(2);
}
HandleTable
ObjectOutputStream 中的内部类。
ReplaceTable
ObjectOutputStream 中的内部类。
ObjectStreamClass
这个类的目的是获取目标类的一些元信息,所以其构造方法需要传入目标类的class 对象。
构造方法:
private ObjectStreamClass(final Class<?> cl) {
this.cl = cl;
name = cl.getName();//获取class 的全名
isProxy = Proxy.isProxyClass(cl); //是否是代理的类
isEnum = Enum.class.isAssignableFrom(cl);//是否是 Enum类型
serializable = Serializable.class.isAssignableFrom(cl);//是否实现了Serializable接口
externalizable = Externalizable.class.isAssignableFrom(cl);//是否实现了Externalizable接口
Class<?> superCl = cl.getSuperclass();//获取父类
superDesc = (superCl != null) ? lookup(superCl, false) : null;
//递归 把父类 处理 为ObjectStreamClass(class)的对象
localDesc = this;
//一般走这个if
if (serializable) {//实现Serializable和Externalizable 接口
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
if (isEnum) {
suid = Long.valueOf(0);
fields = NO_FIELDS;
return null;
}
if (cl.isArray()) {
fields = NO_FIELDS;
return null;
}
suid = getDeclaredSUID(cl);//获取sid
try {//获取序号序列化的字段,并把字段安装升序排列
fields = getSerialFields(cl);
computeFieldOffsets();//计算每个字段在内存中的偏移量
} catch (InvalidClassException e) {
serializeEx = deserializeEx =
new ExceptionInfo(e.classname, e.getMessage());
fields = NO_FIELDS;
}
if (externalizable) {
cons = getExternalizableConstructor(cl);
} else {//一般走这个else
cons = getSerializableConstructor(cl);//获取空参构造方法
writeObjectMethod = getPrivateMethod(cl, "writeObject",
new Class<?>[] { ObjectOutputStream.class },
Void.TYPE);
//获取私有的非静态writeObject方法
readObjectMethod = getPrivateMethod(cl, "readObject",
new Class<?>[] { ObjectInputStream.class },
Void.TYPE);
//获取私有的非静态readObject方法
readObjectNoDataMethod = getPrivateMethod(
cl, "readObjectNoData", null, Void.TYPE);
获取私有的非静态readObjectNoData方法
hasWriteObjectData = (writeObjectMethod != null);//用户自己的 序列化写方法
}
domains = getProtectionDomains(cons, cl);
writeReplaceMethod = getInheritableMethod(
cl, "writeReplace", null, Object.class);
//是否实现了writeReplace 父类方法
readResolveMethod = getInheritableMethod(
cl, "readResolve", null, Object.class);
//是否实现了readResolve 父类方法
return null;
}
});
} else {
suid = Long.valueOf(0);
fields = NO_FIELDS;
}
try {
fieldRefl = getReflector(fields, this);
} catch (InvalidClassException ex) {
// field mismatches impossible when matching local fields vs. self
throw new InternalError(ex);
}
if (deserializeEx == null) {
if (isEnum) {
deserializeEx = new ExceptionInfo(name, "enum type");
} else if (cons == null) {
deserializeEx = new ExceptionInfo(name, "no valid constructor");
}
}
for (int i = 0; i < fields.length; i++) {
if (fields[i].getField() == null) {
defaultSerializeEx = new ExceptionInfo(
name, "unmatched serializable field(s) declared");
}
}
initialized = true;
}
计算字段偏移量
* B byte
* C char
* D double
* F float
* I int
* J long
* L class or interface
* S short
* Z boolean
* [ array
一个普通类obj(只实现Serializable接口)的序列化过程
1.writeStreamHeader buf STREAM_MAGIC(short,pos=2),STREAM_VERSION(short,pos=4)
buf写到输出流 pos=0
blkMode=true
2.
2.1 blkMode=flase,pos=0
基于obj的getClass构造ObjectStreamClass的描述信息类desc
buf append TC_OBJECT pos = 1
2.2 writeClassDesc -> writeNonProxyDesc buf append TC_CLASSDESC pos =2
写 writeClassDescriptor
buf append obj.getClass full name pos = 2+length(name) + 1 这个1 是因为 string 是要先写这个str的长度,再写str的value
buf append sid pos = 2+length(name) + 1 + 8
buf append flag(是否实现externalizable,serializable,hasWriteObjectData,isEnum) pos = 2+length(name) + 1 + 8 + 1
out.writeShort(fields.length) buf append fieldsLength pos = 2+length(name) + 1 + 8 + 1 + 2
循环写属性(已排序) 属性类型,属性名称,非基本类型的属性需要写其类型名称 pos = pos + xxx
2.3 blkMode=true,pos!=0 buf 数据写到 输出流中 ,pos = 0
2.4 blkMode=false,pos=0
2.5 buf append TC_ENDBLOCKDATA pos = 1
2.6 如果有 父类的话,则会跳到2.2步 ,直至没有父类,
否则 buf append TC_NULL pos = 2
3.writeSerialData 获取obj的父类,父类的父类,最后再经过 倒序排序,目的是先写顶级依赖类的属性的值。然后再写顶级依赖类的下一层类的属性值。
3.1 先写基本类型 的值 这个时候 buf中的内容先写到输出流中 pos = 0
再把 属性值 append 到 buf buf!=0
接下来写 非基本类型的属性值 这种方式就是obj的序列化过程了,只不过不用写 序列化的header而已。
4.blkMode=true,buf写到输出流
可以看出,在drain中,是没有用到writeBlockHeader方法的,它其实是为了java旧版本的兼容引入的。
一个String类型(只实现Serializable接口)的序列化过程
1.writeStreamHeader buf STREAM_MAGIC(short,pos=2),STREAM_VERSION(short,pos=4)
buf写到输出流 pos=0
blkMode=true
2.
2.1 blkMode=flase,pos=0
基于obj的getClass构造ObjectStreamClass的描述信息类desc
2.2获取 这个string 的长度,
如果长度小于等于0xFFFF,buf append TC_STRING、append length(string)、写string
如果长度大于0xFFFF,buf append TC_LONGSTRING、append length(string)、写string
3. blkMode=true,buf写到输出流
一个数组类型(只实现Serializable接口)的序列化过程
1.writeStreamHeader buf STREAM_MAGIC(short,pos=2),STREAM_VERSION(short,pos=4)
buf写到输出流 pos=0
blkMode=true
2.
2.1 blkMode=flase,pos=0
2.2 buf append TC_ARRAY pos = 1
2.3 writeClassDesc -> writeNonProxyDesc buf append TC_CLASSDESC pos =2
写 writeClassDescriptor
buf append obj.getClass full name pos = 2+length(name) + 1 这个1 是因为 string 是要先写这个str的长度,再写str的value
buf append sid pos = 2+length(name) + 1 + 8
buf append flag(是否实现externalizable,serializable,hasWriteObjectData,isEnum) pos = 2+length(name) + 1 + 8 + 1
out.writeShort(fields.length) buf append fieldsLength pos = 2+length(name) + 1 + 8 + 1 + 2
循环写属性(已排序) 属性类型,属性名称,非基本类型的属性需要写其类型名称 pos = pos + xxx
2.4 获取数组类型 如果是java基本类型,则会直接转化为对应的 byte。
2.5 如果是非java基本类型,先 buf append 数组长度,然后 和写普通的java class 一致参考 一个普通类obj(只实现Serializable接口)的序列化过程 2.1
对Java 序列化和反序列化的理解和反思
从目前来看,一个普通 Object 的序列化的时候,会写一些这个Class的元信息进去,但不是所有的Class元信息进去的。
所以对应的在 反序列化的时候, 它的应用只能是 Object 类型的。
在阅读 反序列化源码的 readNonProxyDesc 时候,可以看到 resolveClass(readDesc)) 这行代码,里面依旧是 使用 反射机制 返回这个 类 的 class对象。使用反射机制的前提是 本地 jar 里面存在这个类的 class文件,所以一般在分布式环境下,每个节点都必须先要存在这个 类的class文件。
那么,在大数据分布式环境下,是否也可以支持这个 类 class元信息的序列化,这样的话可以不必要求每个节点的 class文件先存在的。在 反序列一个 对象的时候,先反序列化这个对象的Class对象并加载到JVM,再通过这个 class 对象 cast (反序列化后得到的 object对象),就可以避免 用户手动强转object类型到自己的java类型。