五种单例设计模式以及反射攻击改进
程序员文章站
2022-03-09 21:52:32
...
饿汉式(推荐用)
- 效率高
- 线程安全
- 不支持懒加载
public class MySingleClass01 {
//私有化构造方法
private MySingleClass01(){}
//声明本类对象,并使用private static修饰
private static MySingleClass01 instance = new MySingleClass01();
//提供外部获取方法
public static MySingleClass01 getInstance (){
return instance;
}
}
饿汉式
- 效率高
- 线程不安全
- 支持懒加载
public class MySingleClass02 {
//私有化构造方法
private MySingleClass02(){}
//声明本类对象的引用
private static MySingleClass02 instance ;
//提供外部获取方法
public static MySingleClass02 getInstance (){
if(instance==null){
instance=new MySingleClass02();
}
return instance;
}
}
静态内部类单例设计模式(推荐用)
- 效率高
- 线程安全
- 支持懒加载
public class MySingleClass03 {
private MySingleClass03(){}
static class MySingleClassHolder{
private static MySingleClass03 instance = new MySingleClass03();
}
public static MySingleClass03 getInstance(){
return MySingleClassHolder.instance;
}
}
同步懒汉单例设计模式
- 效率非常低
- 线程安全
- 支持懒加载
public class MySingleClass04 {
private MySingleClass04(){}
private static MySingleClass04 instance;
public static MySingleClass04 getInstance(){
synchronized (MySingleClass04.class){
if(instance==null){
instance=new MySingleClass04();
}
}
return instance;
}
}
双重锁单例设计模式(推荐用)
- 效率高
- 线程安全
- 支持懒加载
public class MySingleClass05 {
private MySingleClass05(){}
private static MySingleClass05 instance;
public static MySingleClass05 getInstance(){
if(instance==null){
synchronized (MySingleClass04.class){
if(instance==null){
instance=new MySingleClass05();
}
}
}
return instance;
}
}
通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。但是通过反射可以突破单例设计模式的唯一性。
public class demo06 {
public static void main(String[] args) throws Exception {
//饿汉单例设计模式
MySingleClass01 instance01 = MySingleClass01.getInstance();
Constructor<MySingleClass01> c1 = MySingleClass01.class.getDeclaredConstructor();
c1.setAccessible(true);
MySingleClass01 instance02 = c1.newInstance();
System.out.println(instance01==instance02);
System.out.println("------------------------------------------------------------");
//双重锁单例设计模式
MySingleClass05 instance3 = MySingleClass05.getInstance();
Constructor<MySingleClass05> c2 = MySingleClass05.class.getDeclaredConstructor();
c2.setAccessible(true);
MySingleClass05 instance4 = c2.newInstance();
System.out.println(instance3==instance4);
System.out.println("------------------------------------------------------------");
//静态内部类单例设计模式
MySingleClass03 instance5 = MySingleClass03.getInstance();
Constructor<MySingleClass03> c3 = MySingleClass03.class.getDeclaredConstructor();
c3.setAccessible(true);
MySingleClass03 instance6 = c3.newInstance();
System.out.println(instance5==instance6);
System.out.println("------------------------------------------------------------");
}
}
运行后得到的结果
所以我们需要对这些单例设计模式做进一步的改进。使他们防止反射的攻击。这里以饿汉单例设计模式;双重锁单例设计模式;静态内部类单例设计模式为例子。
public class MySingleClass01 {
//私有化构造方法
private MySingleClass01(){
if(instance!=null){
throw new RuntimeException("已经存在对象了!");
}
}
//声明本类对象,并使用private static修饰
private static MySingleClass01 instance = new MySingleClass01();
//提供外部获取方法
public static MySingleClass01 getInstance (){
return instance;
}
}
再次使用反射,会抛出异常
public class MySingleClass05 {
private MySingleClass05(){
if(instance==null){
throw new RuntimeException("已经存在对象了!");
}
}
private static MySingleClass05 instance;
public static MySingleClass05 getInstance(){
if(instance==null){
synchronized (MySingleClass04.class){
if(instance==null){
instance=new MySingleClass05();
}
}
}
return instance;
}
}
运行后,抛错误
public class MySingleClass03 {
private MySingleClass03(){
if(MySingleClass03.getInstance()!=null){
throw new RuntimeException("已经存在对象了");
}
}
static class MySingleClassHolder{
private static MySingleClass03 instance = new MySingleClass03();
}
public static MySingleClass03 getInstance(){
return MySingleClassHolder.instance;
}
}
运行后,抛错误
总结:每次创建对象,都会走无参构造器,因此在无参构造器中对对象的实例进行是否为空判断,如果是非空,就抛出异常。则可以防止反射攻击,但是无法防止序列话攻击,只有枚举可以防止序列话攻击。