灯火互联
管理员
管理员
  • 注册日期2011-07-27
  • 发帖数41778
  • QQ
  • 火币41290枚
  • 粉丝1086
  • 关注100
  • 终身成就奖
  • 最爱沙发
  • 忠实会员
  • 灌水天才奖
  • 贴图大师奖
  • 原创先锋奖
  • 特殊贡献奖
  • 宣传大使奖
  • 优秀斑竹奖
  • 社区明星
阅读:2798回复:0

java的序列化机制原理分析

楼主#
更多 发布于:2012-09-08 09:45

我们查看下ObjectOutputStream的writeObject方法

[java]
  
//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,然后覆盖其两个方法
[java]
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方法:
[java]
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,如何做这个序列化的过程:
[java]
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方法:
[java]
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进行序列化

[java]
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)的实现:
[java]
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.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)方法:
[java]
        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;
            out.writeByte(f.getTypeCode()); //typecode参考ObjectStreamField.java
            out.writeUTF(f.getName());
            if (!f.isPrimitive()) {
                out.writeTypeString(f.getTypeString());
            }
        }
    }

typecode:
[java]
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数据的过程

[java]
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.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,  
                             fields[numPrimFields + i].isUnshared()); //递归调用writeObject0写入每个field的数据
            } finally {
                if (extendedDebugInfo) {
                    debugInfoStack.pop();
                }      
            }        
        }
    }

当然ObjectInputStream也类似。


喜欢0 评分0
游客

返回顶部