单例模式安全问题--序列化破坏单例模式

通过序列化和反序列化拿到了不同的对象。
先实现序列化接口:

package com.geely.design.pattern.creational.singleton;

import java.io.Serializable;

/**
 * Created by geely
 */
public class HungrySingleton implements Serializable{
    // 准备阶段会被分配内存,但不会被赋予null值,在初始化阶段被初始化。
    private final static HungrySingleton hungrySingleton;

    static{
        hungrySingleton = new HungrySingleton();
    }

    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
    private HungrySingleton(){
        if(hungrySingleton != null){
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

}

测试类

package com.geely.design.pattern.creational.singleton;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * Created by geely
 */
public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(hungrySingleton);

        File file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        HungrySingleton newHungrySingleton = (HungrySingleton) ois.readObject();

        System.out.println(hungrySingleton);
        System.out.println(newHungrySingleton);
        System.out.println(hungrySingleton == newHungrySingleton);
    }
}

运行结果:


图片.png

解决方法:
添加readResolve()方法并且返回原先创建好的HungrySingleton对象

public class HungrySingleton implements Serializable{
    // 准备阶段会被分配内存,但不会被赋予null值,在初始化阶段被初始化。
    private final static HungrySingleton hungrySingleton;

    static{
        hungrySingleton = new HungrySingleton();
    }

    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
    private HungrySingleton(){
        if(hungrySingleton != null){
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }
    private Object readResolve(){
        return hungrySingleton;
    }
}

原理解释:


图片.png

obj这个对象是通过反射创建出来的对象,desc对象是一个ObjectSteam类的对象。既然是通过反射创建出来的新对象,自然和之前的对象不是同一个。这也就解释了为什么刚刚通过序列化和反序列化破坏了单例模式。

你可能感兴趣的:(单例模式安全问题--序列化破坏单例模式)