序列化反序列化源碼分析以及Mybatis中的實際運用

 目錄

  • 序列化
  • 反序列化
  • Mybatis中的實際使用

 

 

   主要知識點:java

  •      writeObject
  •      writeReplace
  •      readObject
  •      readResolve

序列化與反序列化的定義

            序列化就是將對象轉爲字節碼的過程,反序列化則是將字節碼轉換爲對象的過程ide

序列化

     JAVA序列化

       java.io.ObjectOutputStream表明對象輸出流,它的writeObject(Object obj)方法可對參數指定的obj對象進行序列化,把獲得的字節序列寫到一個目標輸出流中。
  java.io.ObjectInputStream表明對象輸入流,它的readObject()方法從一個源輸入流中讀取字節序列,再把它們反序列化爲一個對象,並將其返回。
  只有實現了Serializable和Externalizable接口的類的對象才能被序列化。Externalizable接口繼承自 Serializable接口,實現Externalizable接口的類徹底由自身來控制序列化的行爲,而僅實現Serializable接口的類能夠 採用默認的序列化方式 。
  一般對象序列化包括以下步驟:
  1) 建立一個對象輸出流,它能夠包裝一個其餘類型的目標輸出流,如文件輸出流;
  2) 經過對象輸出流的writeObject()方法寫對象。

  對象反序列化的步驟以下:
  1) 建立一個對象輸入流,它能夠包裝一個其餘類型的源輸入流,如文件輸入流;
  2) 經過對象輸入流的readObject()方法讀取對象。測試

    經過測試代碼分析序列化執行過程,經過本文能夠理解writeObject,writeReplace方法的執行順序,以及序列化執行的具體過程。this

public class Author implements Serializable {

  protected int id;
  protected String username;
  protected String password;
  protected String email;
  protected String bio;
  protected Section favouriteSection;

  public Author() {
    this(-1, null, null, null, null, null);
  }

  public Author(Integer id, String username, String password, String email, String bio, Section section) {
    this.id = id;
    this.username = username;
    this.password = password;
    this.email = email;
    this.bio = bio;
    this.favouriteSection = section;
  }

  public Author(int id) {
    this(id, null, null, null, null, null);
  }

  public void setId(int id) {
    this.id = id;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public void setBio(String bio) {
    this.bio = bio;
  }

  public void setFavouriteSection(Section favouriteSection) {
    this.favouriteSection = favouriteSection;
  }

  public int getId() {
    return id;
  }

  public String getUsername() {
    return username;
  }

  public String getPassword() {
    return password;
  }

  public String getEmail() {
    return email;
  }

  public String getBio() {
    return bio;
  }

  public Section getFavouriteSection() {
    return favouriteSection;
  }


  private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    System.out.println("readObject");
    in.defaultReadObject();
  }


  private void writeObject(ObjectOutputStream out) throws  IOException{
    System.out.println("writeObject");
    out.defaultWriteObject();
  }

  Object writeReplace() throws ObjectStreamException{
    System.out.println("writeReplace");
    Author replaced=new Author();
    replaced.setId(123);
    return replaced;
  }

  

@Test
  public void testSeria() throws  Exception{
    Author author=new Author();
    author.setId(456);
    Serializable result= deserialize(serialize((Serializable)author));
    System.out.println(((Author)result).getId());
  }
 protected byte[] serialize(Serializable value) throws Exception {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(value);
    oos.flush();
    oos.close();
    return bos.toByteArray();
  }

  protected Serializable deserialize(byte[] value) throws Exception {
    ByteArrayInputStream bis = new ByteArrayInputStream(value);
    ObjectInputStream ois = new ObjectInputStream(bis);
    Serializable result = (Serializable) ois.readObject();
    ois.close();
    return result;
  }

  

上面的測試代碼咱們序列化的是ID是456的Author對象,可是反序列化後的對象確實123.debug

writeReplace
writeObject
readObject
123

    這樣彷佛和文章開頭介紹的序列化只是不同,這個是哪裏除了問題呢?在上文說了一般的序列化是如上文所說處理的,可是在ObjectOuputStream中還有一個writeReplace方法,經過該方法能夠替換掉原來須要序列化的對象,時序圖以下所示:3d

經過測試代碼能夠發現,序列化過程以下:代理

--> writeObject
     |
     |--->writeObject0
        |
        |--->writeOrdinaryObject
            |
            |---->invokeWriteReplace
                |
                |--->writeReplaceMethod.invoke   

 

  相關源碼以下:code

        在調用writeObject方法時會判斷須要序列化對象是否存在writeReplace方法,若是存在則會調用該方法獲得一個新的目標對象,並將其進行序列化orm

 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;
        }
    }

  

private void writeObject0(Object obj, boolean unshared)
        throws IOException
    {
       。。。。
            for (;;) {
                // REMIND: skip this check for strings/arrays?
                Class<?> repCl;
                desc = ObjectStreamClass.lookup(cl, true);
                //若是存在writeReplace方法,調用須要序列化對象的writeReplace方法,若是返回對象不爲null且writeReplace返回對象和原序列化對象類相同則退出循環
                if (!desc.hasWriteReplaceMethod() ||
                    (obj = desc.invokeWriteReplace(obj)) == null ||
                    (repCl = obj.getClass()) == cl)
                {
                    break;
                }
                cl = repCl;
            }
            
        。。。

            // 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) { //若是實現了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);
        }
    }


     private void writeOrdinaryObject(Object obj,
                                     ObjectStreamClass desc,
                                     boolean unshared)
        throws IOException
    {
    。。。
        try {
            desc.checkSerialize();

            bout.writeByte(TC_OBJECT);
            writeClassDesc(desc, false);
            handles.assign(unshared ? null : obj);
            if (desc.isExternalizable() && !desc.isProxy()) {
                writeExternalData((Externalizable) obj);
            } else {//寫序列化數據
                writeSerialData(obj, desc);
            }
        } finally {
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }
    }


    private void writeSerialData(Object obj, ObjectStreamClass desc)
        throws IOException{
                。。。
                try {
                    curContext = new SerialCallbackContext(obj, slotDesc);
                    bout.setBlockDataMode(true);
                    //調用序列化對象的writeObject方法
                    slotDesc.invokeWriteObject(obj, this);
                    bout.setBlockDataMode(false);
                    bout.writeByte(TC_ENDBLOCKDATA);
                } finally {
                    curContext.setUsed();
                    curContext = oldContext;
                    if (extendedDebugInfo) {
                        debugInfoStack.pop();
                    }
                }
        }
    }

  反序列化

上面主要講述了序列化的相關知識,那麼反序列化呢?下面就介紹一下反序列化步驟。對象

 

主要的幾個方法以下:

 

-->readObject
  |
  \-->readObject0
     |
     \--->readOrdinaryObject
        |
        |--->invokeReadObject
        |      |
        |     \--->readObjectMethod.invoke

        \------>invokeReadReslove

 

public final Object readObject() throws IOException, ClassNotFoundException {
        if (enableOverride) {
            return readObjectOverride();
        }

        // if nested read, passHandle contains handle of enclosing object
        int outerHandle = passHandle;
        try {
             //調用readObject0方法完成反序列化
            Object obj = readObject0(false);
            handles.markDependency(outerHandle, passHandle);
            ClassNotFoundException ex = handles.lookupException(passHandle);
            if (ex != null) {
                throw ex;
            }
            if (depth == 0) {
                vlist.doCallbacks();
            }
            return obj;
        } finally {
            passHandle = outerHandle;
            if (closed && depth == 0) {
                clear();
            }
        }
    }

  

private Object readObject0(boolean unshared) throws IOException {
       。。。。
        try {
            switch (tc) {
                case TC_NULL:
                    return readNull();

                case TC_REFERENCE:
                    return readHandle(unshared);

                case TC_CLASS:
                    return readClass(unshared);

                case TC_CLASSDESC:
                case TC_PROXYCLASSDESC:
                    return readClassDesc(unshared);

                case TC_STRING:
                case TC_LONGSTRING:
                    return checkResolve(readString(unshared));

                case TC_ARRAY:
                    return checkResolve(readArray(unshared));

                case TC_ENUM:
                    return checkResolve(readEnum(unshared));

                case TC_OBJECT://對象的反序列化
                    return checkResolve(readOrdinaryObject(unshared));

                case TC_EXCEPTION:
                    IOException ex = readFatalException();
                    throw new WriteAbortedException("writing aborted", ex);

                case TC_BLOCKDATA:
                case TC_BLOCKDATALONG:
                    if (oldMode) {
                        bin.setBlockDataMode(true);
                        bin.peek();             // force header read
                        throw new OptionalDataException(
                            bin.currentBlockRemaining());
                    } else {
                        throw new StreamCorruptedException(
                            "unexpected block data");
                    }

                case TC_ENDBLOCKDATA:
                    if (oldMode) {
                        throw new OptionalDataException(true);
                    } else {
                        throw new StreamCorruptedException(
                            "unexpected end of block data");
                    }

                default:
                    throw new StreamCorruptedException(
                        String.format("invalid type code: %02X", tc));
            }
        } finally {
            depth--;
            bin.setBlockDataMode(oldMode);
        }
    }

  

private Object readOrdinaryObject(boolean unshared) throws IOException{
        if (bin.readByte() != TC_OBJECT) {
            throw new InternalError();
        }

        ObjectStreamClass desc = readClassDesc(false);
        desc.checkDeserialize();

        Class<?> cl = desc.forClass();
        if (cl == String.class || cl == Class.class
                || cl == ObjectStreamClass.class) {
            throw new InvalidClassException("invalid class descriptor");
        }

        Object obj;
        try {
            obj = desc.isInstantiable() ? desc.newInstance() : null;
        } catch (Exception ex) {
            throw (IOException) new InvalidClassException(
                desc.forClass().getName(),
                "unable to create instance").initCause(ex);
        }

        passHandle = handles.assign(unshared ? unsharedMarker : obj);
        ClassNotFoundException resolveEx = desc.getResolveException();
        if (resolveEx != null) {
            handles.markException(passHandle, resolveEx);
        }
        //完成對象的反序列化
        if (desc.isExternalizable()) {
            readExternalData((Externalizable) obj, desc);
        } else {
            readSerialData(obj, desc);
        }

        handles.finish(passHandle);
        //若是這個對象實現了readResolve方法則調用該方法
        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod())
        {
            Object rep = desc.invokeReadResolve(obj);
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {
                handles.setObject(passHandle, obj = rep);
            }
        }

        return obj;
    }

  Mybatis中的實際使用  

Mybatis是如何保證序列化和反序列化後的對象仍是支持延遲加載的呢?
在EnhancedResultObjectProxyImpl類中有以下代碼,在該方法中實現了延遲加載,和序列化處理,若是有延遲加載屬性,在調用writeRepalce方法返回的不是代理對象也不是原始對象,而是一個狀態保持的對象。而對狀態保持對象進行反序列化的時候有再次根據序列化的信息建立了一個代理對象
@Override
    public Object invoke(Object enhanced, Method method, Method methodProxy, Object[] args) throws Throwable {
      final String methodName = method.getName();
      try {
        synchronized (lazyLoader) {
          //若是當前調用是writeReplace 則表示須要對象當前對象進行序列化,而當前對象是一個代理對象,直接對當前對象序列化顯然是不合理的
          //在上面的代碼能夠發現代理對對象都存在writeReplace方法,在序列化的時候會調用該方法,在對該方法進行加強處理返回原始對對象,若是須要延遲加載
          //則返回了一個序列化狀態保持對象
          if (WRITE_REPLACE_METHOD.equals(methodName)) {
            Object original;
            //建立一個新的原始對象
            if (constructorArgTypes.isEmpty()) {
              original = objectFactory.create(type);
            } else {
              original = objectFactory.create(type, constructorArgTypes, constructorArgs);
            }
            //複製屬性
            PropertyCopier.copyBeanProperties(type, enhanced, original);
            //若是存在延遲加載對象則建立一個代理對象
            if (lazyLoader.size() > 0) {
              return new JavassistSerialStateHolder(original, lazyLoader.getProperties(), objectFactory, constructorArgTypes, constructorArgs);
            } else {//若是沒有延遲加載對象
              return original;
            }
          } else {// 若是不是writeReplace方法
            //若是懶加載對象大於0且當前不是finalize方法
            if (lazyLoader.size() > 0 && !FINALIZE_METHOD.equals(methodName)) {
              //若是是積極的懶加載模式或者調用列觸發加載所有方法則加載所有懶加載屬性
              if (aggressive || lazyLoadTriggerMethods.contains(methodName)) {
                lazyLoader.loadAll();
              } else if (PropertyNamer.isSetter(methodName)) {
                //若是setter的屬性是懶加載的則從懶加載映射表中刪除
                final String property = PropertyNamer.methodToProperty(methodName);
                lazyLoader.remove(property);
              } else if (PropertyNamer.isGetter(methodName)) {
                //若是getter的屬性是懶加載的此時須要加載
                final String property = PropertyNamer.methodToProperty(methodName);
                if (lazyLoader.hasLoader(property)) {
                  lazyLoader.load(property);
                }
              }
            }
          }
        }
        return methodProxy.invoke(enhanced, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
  }

  

  @Override
  public final void writeExternal(final ObjectOutput out) throws IOException {
    boolean firstRound = false;
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream os = stream.get();
    if (os == null) {
      os = new ObjectOutputStream(baos);
      firstRound = true;
      stream.set(os);
    }
    //序列化userBean
    os.writeObject(this.userBean);
    //序列化未加載屬性
    os.writeObject(this.unloadedProperties);
    //序列化對象工廠
    os.writeObject(this.objectFactory);
    //序列化構造參數類型
    os.writeObject(this.constructorArgTypes);
    //序列化構造參數
    os.writeObject(this.constructorArgs);

    final byte[] bytes = baos.toByteArray();
    //完成序列化
    out.writeObject(bytes);

    if (firstRound) {
      stream.remove();
    }
  }

  @Override
  public final void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
    //反序列化
    final Object data = in.readObject();
    if (data.getClass().isArray()) {
      this.userBeanBytes = (byte[]) data;
    } else {
      this.userBean = data;
    }
  }

  @SuppressWarnings("unchecked")
  protected final Object readResolve() throws ObjectStreamException {
    //若是userBean不爲null且userBeanBytes長度爲0則表示已經完成過 直接返回該對象
    if (this.userBean != null && this.userBeanBytes.length == 0) {
      return this.userBean;
    }

    /*第一次 */
    try {
      final ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(this.userBeanBytes));
      //反序列化userBean
      this.userBean = in.readObject();
      //反序列化延遲加載屬性
      this.unloadedProperties = (Map<String, ResultLoaderMap.LoadPair>) in.readObject();
      //反序列化對象工廠
      this.objectFactory = (ObjectFactory) in.readObject();
      //反序列化構造參數類型
      this.constructorArgTypes = (Class<?>[]) in.readObject();
      //反序列化構造參數
      this.constructorArgs = (Object[]) in.readObject();
    } catch (final IOException ex) {
      throw (ObjectStreamException) new StreamCorruptedException().initCause(ex);
    } catch (final ClassNotFoundException ex) {
      throw (ObjectStreamException) new InvalidClassException(ex.getLocalizedMessage()).initCause(ex);
    }

    final Map<String, ResultLoaderMap.LoadPair> arrayProps = new HashMap<String, ResultLoaderMap.LoadPair>(this.unloadedProperties);
    final List<Class<?>> arrayTypes = Arrays.asList(this.constructorArgTypes);
    final List<Object> arrayValues = Arrays.asList(this.constructorArgs);
     //根據序列化是保存的數據建立一個反序列化代理對象
    return this.createDeserializationProxy(userBean, arrayProps, objectFactory, arrayTypes, arrayValues);
  }
相關文章
相關標籤/搜索