美文网首页
序列化破坏单例&反射破坏单例

序列化破坏单例&反射破坏单例

作者: 别拿爱情当饭吃 | 来源:发表于2019-07-16 22:06 被阅读0次

反序列化破坏单例

public class HungrySingleton implements Serializable {


    private static final HungrySingleton singleton;
    private static final long serialVersionUID = 2389789839637172279L;

    private HungrySingleton(){}

    static {
        singleton = new HungrySingleton();
    }

    public static HungrySingleton getInstance(){
        return singleton;
    }

    /**
     * readResolve方法,如果没这个方法,就反序列化就会破坏单例。
     * 有这个方法,反序列化就不会破坏单例。
     * 这个方法的方法名一定要是:readResovle()
     * @return
     */
    public Object readResolve(){
        return singleton;
    }
}

为什么写了readResolve方法,反序列化就不会破坏单例呢?原因如下:
ObjectInputStream的readOrdinaryObject(boolean unshared)方法

   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方法,就调用readResovle方法
        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod())
        {
            //反射调用ReadResolve方法
            Object rep = desc.invokeReadResolve(obj);
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {
                handles.setObject(passHandle, obj = rep);
            }
        }

        return obj;
    }

反射破坏单例

HungrySingleton singleton = HungrySingleton.getInstance();
        Class<HungrySingleton> clazz = HungrySingleton.class;
        Constructor<HungrySingleton> declaredConstructor = clazz.getDeclaredConstructor();
        //主要就是反射可以破坏封装性,因此破坏单例也是允许的
        declaredConstructor.setAccessible(true);
        HungrySingleton newInstance = declaredConstructor.newInstance();

        System.out.println(singleton);
        System.out.println(newInstance);
        System.out.println(singleton==newInstance);

相关文章

  • 设计模式——单例模式

    文章概要 1、什么是单例2、为什么需要单例3、单例的优点和缺点4、单例的写法和比较5、序列化破坏单例6、反射破坏单...

  • java中你的单例在裸奔吗?

    在上一篇文章java中你确定用对单例了吗?中提到单例可以被恶意的破坏,如序列化破坏和反射破坏单例的结构,好的,这个...

  • 一个简单安全又好用的单例写法,你学废了吗?

    项目里使用枚举写单例: 1、简洁 写法简单 2、懒加载 3、线程安全 4、防止反序列化破坏单例 5、防止反射破坏单...

  • 反射破坏单例模式(静态内部类)

    java反射,破坏单例模式 静态内部类 反射实例化单例

  • 序列化破坏单例&反射破坏单例

    反序列化破坏单例 为什么写了readResolve方法,反序列化就不会破坏单例呢?原因如下:ObjectInput...

  • 深度解析单例与序列化之间的爱恨情仇~

    本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏。 单例模式,...

  • 单例与序列化的那些事儿

    本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏。 单例模式,...

  • 枚举实现单例模式

    枚举实现单例模式 前面我们说到序列化和反序列化以及反射对单例都是有破坏的,下面我们介绍一种更加优雅的实现,也是ef...

  • 单例模式

    由于性能问题,优化,采用双重检查锁 懒汉式内部类单例 枚举类从JDK层面就保证不能被序列化和反射所破坏单例模式 枚...

  • 反射的破坏性

    如何防止反射破坏单例? 参考:https://www.jianshu.com/p/5f529f18821a基于单例...

网友评论

      本文标题:序列化破坏单例&反射破坏单例

      本文链接:https://www.haomeiwen.com/subject/bzmxlctx.html