设计模式——单例模式的破坏

2018-12-11  本文已影响0人  linjiajiam

概述:

反射:

public class MainClass {

    public static void main(String[] args) {

        PersonLazyInnerClass person1 = PersonLazyInnerClass.getPersonLazyInnerClass();
        PersonLazyInnerClass person2 = null;
        try {
            Class<PersonLazyInnerClass> cla = PersonLazyInnerClass.class;
            //获得默认构造函数
            Constructor<PersonLazyInnerClass> cons = cla.getDeclaredConstructor();
            //使默认构造函数可访问
            cons.setAccessible(true);
            //创建对象
            person2 = cons.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());
    }
}
public class PersonLazyInnerClassSafe {

    //申明一个标志位,用于标志构造函数是否被调用过
    private static Boolean alreadyNew = false;

    private PersonLazyInnerClassSafe(){
        //加锁防止并发
        synchronized (PersonLazyInnerClassSafe.class){
            //第一次被调用,仅修改标志位;后续被调用抛异常
            if(alreadyNew == false){
                alreadyNew = true;
            }else {
                throw new RuntimeException("单例模式被破坏!");
            }
        }
    }

    private static class Holder{
        private static PersonLazyInnerClassSafe personLazyInnerClassSafe = new PersonLazyInnerClassSafe();
    }

    public static PersonLazyInnerClassSafe getInstance(){
        return Holder.personLazyInnerClassSafe;
    }
}
public class MainClass {

    public static void main(String[] args) {
        //正常执行代码
        PersonLazyInnerClassSafe person1 = PersonLazyInnerClassSafe.getInstance();
        PersonLazyInnerClassSafe person2 = PersonLazyInnerClassSafe.getInstance();
        System.out.println(person1.hashCode());
        System.out.println(person2.hashCode());
    }
}
public class MainClass {

    public static void main(String[] args) {
        //先反射获取单例
        PersonLazyInnerClassSafe person2 = null;
        try {
            Class<PersonLazyInnerClassSafe> cla = PersonLazyInnerClassSafe.class;
            //获得默认构造函数
            Constructor<PersonLazyInnerClassSafe> cons = cla.getDeclaredConstructor();
            //使默认构造函数可访问
            cons.setAccessible(true);
            //调用默认构造函数,创建对象
            person2 = cons.newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("反射对象: " + person2.hashCode());
        //在用正常的方法获取单例,此时会报错
        PersonLazyInnerClassSafe person1 = PersonLazyInnerClassSafe.getInstance();
        System.out.println("正常获取" + person1.hashCode());
    }
}

反序列化:

1. 破坏单例
public class MainClass {

    public static void main(String[] args) {
        //序列化
        PersonLazyInnerClassSafe person3 = PersonLazyInnerClassSafe.getInstance();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tempfile"));
        out.writeObject(PersonLazyInnerClassSafe.getInstance());

        File file  = new File("tempfile");
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        //调用readObject()反序列化
        PersonLazyInnerClassSafe person4 = (PersonLazyInnerClassSafe)in.readObject();
        System.out.println("正常构造:" + person3.hashCode());
        System.out.println("反序列化Person:" + person4.hashCode());
    }
}
    public final Object readObject()
        throws IOException, ClassNotFoundException
    {
        if (enableOverride) {
            return readObjectOverride();
        }

        // if nested read, passHandle contains handle of enclosing object
        int outerHandle = passHandle;
        try {
            Object obj = readObject0(false);  //通过debug会发现进入此方法
            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();
            }
        }
    }

分析readObject0方法,会发现进入了readOrdinaryObject()方法。

    private Object readObject0(boolean unshared) throws IOException {
        boolean oldMode = bin.getBlockDataMode();
        if (oldMode) {
            int remain = bin.currentBlockRemaining();
            if (remain > 0) {
                throw new OptionalDataException(remain);
            } else if (defaultDataEnd) {
                /*
                 * Fix for 4360508: stream is currently at the end of a field
                 * value block written via default serialization; since there
                 * is no terminating TC_ENDBLOCKDATA tag, simulate
                 * end-of-custom-data behavior explicitly.
                 */
                throw new OptionalDataException(true);
            }
            bin.setBlockDataMode(false);
        }

        byte tc;
        while ((tc = bin.peekByte()) == TC_RESET) {
            bin.readByte();
            handleReset();
        }

        depth++;
        try {
            switch (tc) {
                ...省略部分源码

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

obj = desc.isInstantiable() ? desc.newInstance() : null;

   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  //读取Class
                || cl == ObjectStreamClass.class) {
            throw new InvalidClassException("invalid class descriptor");
        }
        
        /**===============关键代码1====================== **/
        Object obj;
        try {
            obj = desc.isInstantiable() ? desc.newInstance() : null;  //通过类描述信息,初始化对象obj。
        } catch (Exception ex) {
            throw (IOException) new InvalidClassException(
                desc.forClass().getName(),
                "unable to create instance").initCause(ex);
        }
         /**===============关键代码1====================== **/
        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);
         /**===============关键代码2====================== **/
        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);
            }
        }
         /**===============关键代码2====================== **/
        return obj;
    }
/** serialization-appropriate constructor, or null if none */
private Constructor<?> cons;
...省略部分源码
Object newInstance()
        throws InstantiationException, InvocationTargetException,
               UnsupportedOperationException
    {
        requireInitialized();
        if (cons != null) {
            try {
                return cons.newInstance();
            } catch (IllegalAccessException ex) {
                // should not occur, as access checks have been suppressed
                throw new InternalError(ex);
            }
        } else {
            throw new UnsupportedOperationException();
        }
    }
public class MainClass {

    public static void main(String[] args) {
        //验证一下反序列化是通过Object的构造函数去反射,生成了新的实例
        PersonLazyInnerClassSafe person3 = PersonLazyInnerClassSafe.getInstance();
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tempfile"));
        out.writeObject(PersonLazyInnerClassSafe.getInstance());

        File file  = new File("tempfile");
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        //反序列化生成的Object对象
        Object ob = in.readObject();
        //将Object强转为PersonLazyInnerClassSafe
        PersonLazyInnerClassSafe person4 = (PersonLazyInnerClassSafe)ob;
        System.out.println("正常构造:" + person3.hashCode());
        System.out.println("反序列化Object:" + ob.hashCode());
        System.out.println("反序列化Person:" + person4.hashCode());
    }
}

//反序列化生成的Object对象
Object ob = in.readObject();
//将Object强转为PersonLazyInnerClassSafe
PersonLazyInnerClassSafe person4 = (PersonLazyInnerClassSafe)ob;

2. 阻止破坏单例
        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod())   //判断对象是否实现readResolve方法  
        {
            Object rep = desc.invokeReadResolve(obj); //反射调用对象的readResolve方法  
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {  //如果对象readResolve返回的对象与 默认序列化对象不等,返回readResolve方法返回的对象  
                handles.setObject(passHandle, obj = rep);
            }
        }
public class PersonLazyInnerClassSafe implements Serializable{

    //申明一个标志位,用于标志构造函数是否被调用过
    public static Boolean alreadyNew = false;

    private PersonLazyInnerClassSafe(){
        System.out.println("调用构造函数!!!");
        //加锁防止并发
        synchronized (PersonLazyInnerClassSafe.class){
            //第一次被调用,仅修改标志位;后续被调用抛异常
            if(alreadyNew == false){
                alreadyNew = true;
            }else {
                throw new RuntimeException("单例模式被破坏!");
            }
        }
    }

    private static class Holder{
        private static PersonLazyInnerClassSafe personLazyInnerClassSafe = new PersonLazyInnerClassSafe();
    }

    public static PersonLazyInnerClassSafe getInstance(){
        return Holder.personLazyInnerClassSafe;
    }

    //阻止序列化破坏单例
    private Object readResolve(){
        return Holder.personLazyInnerClassSafe;
    }
}

总结:

  1. 破坏单例有两种方式 反射、反序列化
  2. 反射破坏的原理是:通过反射获取其默认的构造函数,并且改变其构造函数的访问域,从而实现调用构造函数创建新实例。解决方案是:在构造函数中增加一个标志位,用于判断构造函数是否被调用过,阻止外部能调用类的构造函数一次以上。
  3. 反序列化破坏构造函数的原理:通过Object的构造函数,反射出单例类对象,从而创建了新的实例。解决方案是:在单例类中写一个readResolve()方法,在这个方法中返回我们想要的单例,就可以解决序列化破坏单例。
上一篇 下一篇

猜你喜欢

热点阅读