package instance.lazy;
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
* 懒汉式单例
* @author jingzi
* 单例模式是最常用的设计模式,一个完美的单例需要做到哪些事呢?
* 1、单例
* 2、延迟加载
* 3、线程安全
* 4、没有性能问题
* 5、防止序列化产生新对象
* 6、防止反射攻击
*/
public class LazyType implements Serializable {
private static final long serialVersionUID = 6427931149119200875L;
/**
* 声明为volatile,保证多线程可见性、防止“instance = new LazyType()”指令重排序。
* 注:instance = new LazyType()是非原子性操作。
* instance = null:延迟加载。
*/
private volatile static LazyType instance = null;
private static boolean flag = false;
private LazyType() {
//防止反射攻击
synchronized (LazyType.class) {
if (false == flag) {
flag = !flag;
} else {
//被反射攻击,抛出异常。
throw new RuntimeException("Reflected attack!");
}
}
}
/**
* 执行两次校验:很有必要,这样可以保证线程安全。
* 当多线程调用时,如果多个线程同时执行完了第一次检查,其中一个进入他不代码块创建了实例,
* 后面的线程因第二次检查不会创建实例。
* @return
*/
public static LazyType getInstance() {
if (null == instance) {//第一次检查
synchronized (LazyType.class) {
if (null == instance) {//第二次检查
instance = new LazyType();
}
}
}
return instance;
}
/**
* 如果实现了Serializable, 必须重写这个方法,才能保证其反序列化依旧是单例,即防止序列化产生新对象。
* @return
* @throws ObjectStreamException
*/
private Object readResolve() throws ObjectStreamException {
return instance;
}
/**
* 所执行的业务功能
*/
public void doSomethingElse() {
}
}
测试,防止单例模式被java反射攻击:
package instance.lazy;
import java.lang.reflect.Constructor;
public class LazyTypeModifiedReflectAttack {
public static void main(String[] args){
try {
Class classType = LazyType.class;
Constructor c = classType.getDeclaredConstructor(null);
c.setAccessible(true);
LazyType e1 = (LazyType)c.newInstance();
System.out.println("e1.hashCode():" + e1.hashCode());
LazyType e2 = LazyType.getInstance();
System.out.println("e2.hashCode():" + e2.hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试结果:
e1.hashCode():118352462
java.lang.RuntimeException: Reflected attack!
at instance.lazy.LazyType.(LazyType.java:36)
at instance.lazy.LazyType.getInstance(LazyType.java:50)
at instance.lazy.LazyTypeModifiedReflectAttack.main(LazyTypeModifiedReflectAttack.java:16)
参考内容: