Java for Web学习笔记(八八):消息和集群(3)序列化Serializable

2017-11-12 Bruce_lee

对象序列化

在集群中,涉及到数据在不同的app,不同的JVM,不同的机器之间的。Java通过对象的序列化实现对象在不同app之间传递。在进一步探讨集群之前,我们需要对序列化进行了解。推荐阅读 Java对象表示方式1:序列化、反序列化的作用

对于要求序列化的对象,static和transient是不进行序列化的。我们看看下面简单的小例子,如何通过自定义的序列化和反序列化来实现transient参数的传递:

public class S1 implements Serializable{
    private static final long serialVersionUID = 1L;

    private String str0;
    private transient String str1; //transient不进行序列化,用于在自定义序列化中进行测试。
    private String str2;

    // getters and setters ... 略

    private void writeObject(java.io.ObjectOutputStream s) throws Exception{
        s.defaultWriteObject();
        //增加写入str1对象
        s.writeObject(str1);
    }

    private void readObject(java.io.ObjectInputStream s) throws Exception{
        /* Read the non-static and non-transient fields of the current class from this stream. This may only be called from the readObject method of the class being deserialized. It will throw the NotActiveException if it is called otherwise. 
        * 这里有些特别,调用defaultReadObject()必须在readObject的方法中,但此方法不作为Override。对于writeObject也是同理 */
        s.defaultReadObject();
        //增加读入str1对象
        str1 = (String) s.readObject(); 
    }
}
/** 用于测试序列化和反序列化 */
public class SerialTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        S1 s = new S1();
        s.setStr0("Hello");
        s.setStr1("my");
        s.setStr2("friend");

        File file = new File("D:" + File.separator + "weitest.txt");
        try(OutputStream os = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(os);){
            oos.writeObject(s);
        }

        try(InputStream is = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(is);){
            S1 object = (S1) ois.readObject();
            System.out.println("str0=" + object.getStr0() + ", str1=" + object.getStr1() + ", str2=" + object.getStr2());    
        }
    }
}

ApplicationEvent的序列化

ApplicationEvent是个抽象类,继承了EventObject。我们看看这两个类的源代码

public abstract class ApplicationEvent extends EventObject {
    private static final long serialVersionUID = 7099057708183571937L;

    private final long timestamp;

    public ApplicationEvent(Object source) {
        super(source);
        this.timestamp = System.currentTimeMillis();
    }

    public final long getTimestamp() {
        return this.timestamp;
    }
}
public class EventObject implements java.io.Serializable {
    private static final long serialVersionUID = 5516075349620653480L;

    protected transient Object  source;

    public EventObject(Object source) {
        if (source == null)
            throw new IllegalArgumentException("null source");

        this.source = source;
    }

    public Object getSource() {
        return source;
    }

    public String toString() {
        return getClass().getName() + "[source=" + source + "]";
    }
}

可以看到ApplicationEvent含有long timestamp,transient Object source,而source是我们传递的关键信息,它是transient的,也就是不在序列化的范畴。我们希望将ApplicationEvent的对象通过消息在不同的JVM中传递,必须要将source也序列化,因此:

  1. Object source需要是Serializable source
  2. 通过自定义的序列化和反序列化来实现。
public class ClusterEvent extends ApplicationEvent implements Serializable{    
    private static final long serialVersionUID = 1L;

    //【1】由于EventObject是父类的父类,无法进行修订,增加一个可以序列化的参数Serializable serializableSource来记录source
    private final Serializable serializableSource;

    public ClusterEvent(Serializable source) {
        super(source);
        //1.1)在构造函数中将source记录至可序列化参数serializableSource中
        this.serializableSource = source;
    }

    private void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException{
        in.defaultReadObject();
        //1.2)将反序列化后获得的serializableSource赋值给无法序列化的source
        this.source = this.serializableSource;
    } 
}

相关链接: 我的Professional Java for Web Applications相关文章


用户评论
开源开发学习小组列表