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类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值