`
dawuafang
  • 浏览: 1107951 次
文章分类
社区版块
存档分类
最新评论

java的序列化机制原理分析

 
阅读更多

我们查看下ObjectOutputStream的writeObject方法

 
//final方法,不允许子类覆盖
    public final void writeObject(Object obj) throws IOException {
        if (enableOverride) { //如果开启允许序列化被重写
            writeObjectOverride(obj); //调用子类的序列化重写方法
            return;
        }
        try {
            writeObject0(obj, false);//调用默认的序列化过程
        } catch (IOException ex) {
            if (depth == 0) {
                writeFatalException(ex);
            }
            throw ex;
        }
    }

如果要自定义这个序列化过程,则可以写一个子类,集成ObjectOutputStream,然后覆盖其两个方法

   protected ObjectOutputStream() throws IOException, SecurityException {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
        bout = null;
        handles = null;
        subs = null;
        enableOverride = true;
        debugInfoStack = null;
    }
   protected void writeObjectOverride(Object obj) throws IOException {
    }

我们再看下具体的writeObject0方法:

private void writeObject0(Object obj, boolean unshared) 
        throws IOException 
    {
        boolean oldMode = bout.setBlockDataMode(false);
        depth++;
        try {
            // 先对obj实例的类信息进行序列化,
            int h;
            if ((obj = subs.lookup(obj)) == null) {
                writeNull();
                return;
            } else if (!unshared && (h = handles.lookup(obj)) != -1) {//可以自定义class类信息的序列化handler
                writeHandle(h);
                return;
            } else if (obj instanceof Class) { //类信息序列化
                writeClass((Class) obj, unshared);
                return;
            } else if (obj instanceof ObjectStreamClass) { //类信息序列化,此时还包括serialVersionUID
                writeClassDesc((ObjectStreamClass) obj, unshared);
                return;
            }
            
            // check for replacement object
            //这里还可以对序列化的类进行替换序列化
            Object orig = obj;
            Class cl = obj.getClass();
            ObjectStreamClass desc;
            for (;;) {
                // REMIND: skip this check for strings/arrays?
                Class repCl;
                desc = ObjectStreamClass.lookup(cl, true);
                if (!desc.hasWriteReplaceMethod() ||
                    (obj = desc.invokeWriteReplace(obj)) == null ||
                    (repCl = obj.getClass()) == cl)
                {
                    break;
                }
                cl = repCl;
            }
            if (enableReplace) {
                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) {
                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;
                }
            }

            // remaining cases
            //写入类实例对象的数据,第一次总是在此执行
            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) { //我们的bean需要实现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);
        }
    }

我们先简单的看下如果是一个String,如何做这个序列化的过程:

 private void writeString(String str, boolean unshared) throws IOException {
        handles.assign(unshared ? null : str); 
        long utflen = bout.getUTFLength(str);
        if (utflen <= 0xFFFF) {
            bout.writeByte(TC_STRING);
            bout.writeUTF(str, utflen);
        } else {
            bout.writeByte(TC_LONGSTRING);
            bout.writeLongUTF(str, utflen);
        }
    }

bout的writeUTF方法:

void writeUTF(String s, long utflen) throws IOException {
            if (utflen > 0xFFFFL) {
                throw new UTFDataFormatException();
            }
            writeShort((int) utflen); //先写入长度,
            if (utflen == (long) s.length()) {
                writeBytes(s); //然后写入字节流
            } else {
                writeUTFBody(s);
            }
        }

很简单,就是写入一个字符串的一个字节的标示符,然后写入字符串的字节流。

那么再看看writeOrdinaryObject(obj, desc, unshared);如何对一个bean进行序列化


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(); //检查下是否可以进行序列化,比如socket对象之类的,如果对象无法进行序列化,则抛出异常。

            bout.writeByte(TC_OBJECT); //先写入一个字节的类对象的标示符
            writeClassDesc(desc, false); //序列化对象的class类信息
            handles.assign(unshared ? null : obj); //保存类的seariableID跟对象的映射关系
            if (desc.isExternalizable() && !desc.isProxy()) { //如果我们自定义了对象的序列化过程,则调用对象的writeExternalData方法。如果实现Externalizable
                                                              //    /** true if represented class implements Externalizable */
                                                              // private boolean externalizable;
                writeExternalData((Externalizable) obj);
            } else {
                writeSerialData(obj, desc); //否则调用默认的序列化方法
            }
        } finally {
                if (extendedDebugInfo) {
                debugInfoStack.pop();
            }  
        }
    }

然后我们先看看writeClassDesc(desc, false)的实现:

  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()) { //如果是proxy对象,则调用该序列化机制 ,isProxy的判断
           //isProxy = Proxy.isProxyClass(cl); Returns true if and only if the specified class was dynamically generated to be a proxy class using the getProxyClass method or the newProxyInstance method. 
            writeProxyDesc(desc, unshared);
        } else {
            writeNonProxyDesc(desc, unshared);
        }
    }
    
    /**
     * Writes class descriptor representing a dynamic proxy class to stream.
     */
    private void writeProxyDesc(ObjectStreamClass desc, boolean unshared) 
        throws IOException 
    {
        bout.writeByte(TC_PROXYCLASSDESC); //写入代理对象的标示符
        handles.assign(unshared ? null : desc);

        Class cl = desc.forClass();
        Class[] ifaces = cl.getInterfaces(); //如果是proxy对象,则写入对象的interfaces的名称
        bout.writeInt(ifaces.length); //先写入interface个数
        for (int i = 0; i < ifaces.length; i++) {
            bout.writeUTF(ifaces[i].getName()); //再写入每个interface的名称
        }
        
        bout.setBlockDataMode(true);
        annotateProxyClass(cl);
        bout.setBlockDataMode(false);
        bout.writeByte(TC_ENDBLOCKDATA); //结束标签
        
        writeClassDesc(desc.getSuperDesc(), false);//递归写入父类的序列化信息,因为java是单继承,
    }
    
    /**
     * Writes class descriptor representing a standard (i.e., not a dynamic
     * proxy) class to stream.
     */
    private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared) 
        throws IOException 
    {
        bout.writeByte(TC_CLASSDESC);//写入class对象的标示符
        handles.assign(unshared ? null : desc);
        
        if (protocol == PROTOCOL_VERSION_1) { //如果非代理类对象的具体class信息,查看下面的方法
            // do not invoke class descriptor write hook with old protocol
            desc.writeNonProxy(this);
        } else {
            writeClassDescriptor(desc); 
        }
        
        Class cl = desc.forClass();
        bout.setBlockDataMode(true);
        annotateClass(cl);
        bout.setBlockDataMode(false);
        bout.writeByte(TC_ENDBLOCKDATA);
        
        writeClassDesc(desc.getSuperDesc(), false);//递归写入父类的序列化信息,因为java是单继承,
    }

writeClassDescriptor(desc)方法:

        throws IOException
    {
        desc.writeNonProxy(this);
    }

 void writeNonProxy(ObjectOutputStream out) throws IOException {
        out.writeUTF(name);//写入类的名称
        out.writeLong(getSerialVersionUID());//写入类的SerialVersionUID

        byte flags = 0;
        if (externalizable) {//是否实现externalizable接口
            flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
            int protocol = out.getProtocolVersion();
            if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
                flags |= ObjectStreamConstants.SC_BLOCK_DATA;
            }
        } else if (serializable) {//是否实现serializable接口
            flags |= ObjectStreamConstants.SC_SERIALIZABLE;
        }
        if (hasWriteObjectData) {//是否有自定义的重写序列化方法
            flags |= ObjectStreamConstants.SC_WRITE_METHOD;
        }
        if (isEnum) {
            flags |= ObjectStreamConstants.SC_ENUM;//是否是枚举
        }
        out.writeByte(flags);
        
        out.writeShort(fields.length); //遍历写入各个类的各个field字段类型名称等信息
        for (int i = 0; i < fields.length; i++) {
            ObjectStreamField f = fields[i];
            out.writeByte(f.getTypeCode()); //typecode参考ObjectStreamField.java类
            out.writeUTF(f.getName());
            if (!f.isPrimitive()) {
                out.writeTypeString(f.getTypeString());
            }
        }
    }

typecode:

            case 'Z': type = Boolean.TYPE; break;
            case 'B': type = Byte.TYPE; break;
            case 'C': type = Character.TYPE; break;
            case 'S': type = Short.TYPE; break;
            case 'I': type = Integer.TYPE; break;
            case 'J': type = Long.TYPE; break;
            case 'F': type = Float.TYPE; break;
            case 'D': type = Double.TYPE; break;
            case 'L':
            case '[': type = Object.class; break;

至此,对象obj的class相关信息已经全部写入。

然后我们再查看具体写入obj数据的过程


 private void writeSerialData(Object obj, ObjectStreamClass desc) 
        throws IOException 
    {
        ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
        for (int i = 0; i < slots.length; i++) {
            ObjectStreamClass slotDesc = slots[i].desc;
            if (slotDesc.hasWriteObjectMethod()) { //Returns true if represented class is serializable (but not externalizable) and defines a conformant writeObject method. Otherwise, returns false.
                Object oldObj = curObj;
                ObjectStreamClass oldDesc = curDesc;
                PutFieldImpl oldPut = curPut;
                curObj = obj;
                curDesc = slotDesc;
                curPut = null;

                if (extendedDebugInfo) {
                    debugInfoStack.push(
                        "custom writeObject data (class \"" + 
                        slotDesc.getName() + "\")");
                }        
                try {
                    bout.setBlockDataMode(true);
                    slotDesc.invokeWriteObject(obj, this);
                    bout.setBlockDataMode(false);
                    bout.writeByte(TC_ENDBLOCKDATA);
                } finally {
                    if (extendedDebugInfo) {
                        debugInfoStack.pop();
                    }        
                } 

                curObj = oldObj;
                curDesc = oldDesc;
                curPut = oldPut;
            } else {
                defaultWriteFields(obj, slotDesc); //写入对象的字段数据
            }
        }
    }
    private void defaultWriteFields(Object obj, ObjectStreamClass desc)
        throws IOException
    {
        // REMIND: perform conservative isInstance check here?
        desc.checkDefaultSerialize();

        int primDataSize = desc.getPrimDataSize(); //先写入private field的数据
        if (primVals == null || primVals.length < primDataSize) {
            primVals = new byte[primDataSize];
        }
        desc.getPrimFieldValues(obj, primVals);
        bout.write(primVals, 0, primDataSize, false);
        
        ObjectStreamField[] fields = desc.getFields(false);
        Object[] objVals = new Object[desc.getNumObjFields()];
        int numPrimFields = fields.length - objVals.length;
        desc.getObjFieldValues(obj, objVals);
        for (int i = 0; i < objVals.length; i++) { //写入非private的数据
            if (extendedDebugInfo) {
                debugInfoStack.push(
                    "field (class \"" + desc.getName() + "\", name: \"" + 
                    fields[numPrimFields + i].getName() + "\", type: \"" + 
                    fields[numPrimFields + i].getType() + "\")");
            }        
            try {
                writeObject0(objVals[i], 
                             fields[numPrimFields + i].isUnshared()); //递归调用writeObject0写入每个field的数据
            } finally {
                if (extendedDebugInfo) {
                    debugInfoStack.pop();
                }     
            }        
        }
    }

当然ObjectInputStream也类似。
分享到:
评论

相关推荐

    Java序列化的机制和原理

    Java序列化API提供一种处理对象序列化的标准机制。在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用一个实例来示范序列化以后的字节是如何描述一个对象的信息的。……

    Java序列化的机制和原理[归类].pdf

    Java序列化的机制和原理[归类].pdf

    Java序列化机制与原理的深入分析

    有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍

    【Java面试+Java学习指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    序列化和反序列化 继承、封装、多态的实现原理 容器 Java集合类总结 Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解2:Queue和LinkedList Java集合详解3:Iterator,fail-fast机制...

    JavaEE技术问题汇总.docx

    如何实现Java序列化与反序列化.序列化和反序列化使用的API 如何实现Java中的一个对象中某一个属性不被序列化,如何实现呢? Java中堆内存和栈内存区别 讲一讲反射,主要是概念,都在哪需要反射机制 JSP中有个...

    JAVA反序列化漏洞知识点整理

     反序列化漏洞的本质是反序列化机制打破了数据和对象的边界,导致攻击者注入的恶意序列化数据在反序列化过程中被还原成对象,控制了对象可能在目标系统上面执行攻击代码,而不可信的输入和未检测反序列化对象的...

    Java思维导图xmind文件+导出图片

    理解通信协议传输过程中的序列化和反序列化机制 基于框架的RPC通信技术 WebService/ApacheCXF RMI/Spring RMI Hession 传统RPC技术在大型分布式架构下面临的问题 分布式架构下的RPC解决方案 Zookeeper ...

    java源码包---java 源码 大量 实例

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    Java工程师面试复习指南

    序列化和反序列化 继承封装多态的实现原理 集合类 Java集合类总结 Java集合详解:一文读懂ArrayList,Vector与Stack使用方法和实现原理 Java集合详解:Queue和LinkedList Java集合详解:迭代器,快速失败机制与比较器...

    【大厂面试题总结】JavaSE面试题总结详细教程

    【大厂面试题总结】JavaSE面试题总结详细教程: 目录: 递归算法之输出某个目录下所有文件和子目录列表 泛型中extends和super的区别 ...java序列化方式 java中实现多态的机制 string常量池和intern韩雅茹

    JAVA上百实例源码以及开源项目

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目源代码

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    【大厂面试题总结】JavaSE面试题合集及其答案,基本包括javaSE所有知识点和详细解释

    【大厂面试题总结】JavaSE面试题合集及其答案,基本包括javaSE所有知识点和详细解释 。 JavaSE面试题总结详细教程: 目录: 递归算法之输出某个目录下所有...java序列化方式 java中实现多态的机制 string常量池和intern

    java源码包4

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包3

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包2

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    密钥 Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存...

    Java2实用教程.rar

    10 10序列化与对象克隆 10 11文件锁FileLock 10 12Process类中的流 10 13带进度条的输入流 习题 第11章Java网络的基本知识 11 1使用URL 11 2读取URL中的资源 11 3显示URL资源中的HTML文件 11 4处理超链接 11 5...

    疯狂JAVA讲义

    1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6 1.3.2 Java程序的运行机制和JVM 6 1.4 开发Java的准备 7 1.4.1 安装JDK 8 学生提问:不是说JVM是运行Java程序的虚拟机吗?那JRE和JVM的关系是怎样的呢? 8 ...

Global site tag (gtag.js) - Google Analytics