单例模式破解方法除了反射和序列化还有一种方法

运维

  面试中常常问到单例模式,并且实际中也是经常使用的方式,但单例模式在哪些情况下会被破解呢?被破解了如何应对破解呢?

  反射破解和防破解

  /** * 饿汉式 */public class SingletonTest { private SingletonTest(){ System.out.println("private SingletonTest()"); } private static final SingletonTest INSTANCE = new SingletonTest(); public static SingletonTest getInstance(){ return INSTANCE; } public static void otherMethod(){ System.out.println("otherMethod()"); }}这是一个单例模式,接下来用反射创建这个对象

   public static void main(String[] args) throws Exception { SingletonTest.otherMethod(); System.out.println(SingletonTest.getInstance()); reflection(SingletonTest.class); } private static void reflection(Class<?> clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Constructor<?> constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); System.out.println("反射创建实例:" + constructor.newInstance()); }返回结果

  private SingletonTest()otherMethod()com.whf.mian.shi.single.SingletonTest@3c679bdeprivate SingletonTest()反射创建实例:com.whf.mian.shi.single.SingletonTest@16b4a017如何应对这种情况呢?

  在私有构造函数中增加一下代码,禁止通过反射机制调用

   private SingletonTest(){ if(INSTANCE!=null){ throw new RuntimeException("单例对象不能重复创建"); } System.out.println("private SingletonTest()"); }序列化破坏单例

  单例模式要实现序列化接口,才能够应用于序列化

  /** * 饿汉式 */public class SingletonTest implements Serializable { private SingletonTest(){ System.out.println("private SingletonTest()"); } private static final SingletonTest INSTANCE = new SingletonTest(); public static SingletonTest getInstance(){ return INSTANCE; } public static void otherMethod(){ System.out.println("otherMethod()"); }}通过序列化创建这个对象

  public static void main(String[] args) throws Exception { SingletonTest.otherMethod(); System.out.println(SingletonTest.getInstance()); serializable(SingletonTest.getInstance()); } private static void serializable(Object instance) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(instance); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); System.out.println("反序列化创建实例:"+ois.readObject()); }返回结果

  private SingletonTest()otherMethod()com.whf.mian.shi.single.SingletonTest@3c679bde反序列化创建实例:com.whf.mian.shi.single.SingletonTest@735f7ae5这种情况只需要在单例对象中添加readResolve方法,直接返回该对象即可

   //防止反序列化对象 public Object readResolve(){ return INSTANCE; }

  Unsafe 破坏单例

  使用unsafe创建该对象

   public static void main(String[] args) throws Exception { SingletonTest.otherMethod(); System.out.println(SingletonTest.getInstance()); unsafe(SingletonTest.class); } private static void unsafe(Class<?> clazz) throws InstantiationException, InvocationTargetException, IllegalAccessException, NoSuchMethodException { Constructor<?> constructor = Unsafe.class.getDeclaredConstructor(); constructor.setAccessible(true); Unsafe o1 = (Unsafe) constructor.newInstance(); Object o = o1.allocateInstance(clazz); System.out.println("Unsafe 创建实例:" + o); }返回结果

  private SingletonTest()otherMethod()com.whf.mian.shi.single.SingletonTest@3c679bdeUnsafe 创建实例:com.whf.mian.shi.single.SingletonTest@16b4a017这种方式还不知道怎么预防。

标签: 运维