一、饿汉式的反射攻击及解决方法
public class HungrySingleton {
//直接声明一个需要被单例的对象,在静态块中初始化对象
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton=new HungrySingleton();
}
//私有的构造器,不被外部所访问
private HungrySingleton(){
// 防止反射攻击
if(hungrySingleton !=null ){
throw new RuntimeException("单例构造器进制通过反射调用。。。。");
}
// 防止反射攻击
}
//提供一个外部获取HungrySingleton对象的静态方法
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
public class HungryTest {
public static void main(String[] args) {
try {
/**
* @Description: 通过反射获取对象
* @Author: xz
* @Date: 2020/5/31 21:06
*/
//获取class对象
Class<HungrySingleton> hungrySingletonClass = HungrySingleton.class;
//通过获取的class对象,获取声明的构造器
Constructor<HungrySingleton> declaredConstructor = hungrySingletonClass.getDeclaredConstructor();
//去除构造器的私有权限
declaredConstructor.setAccessible(true);
//通过构造器创建对象
HungrySingleton newInstance = declaredConstructor.newInstance();
/**
* @Description: 直接通过类名.getInstance方法获取对象
* @Author: xz
* @Date: 2020/5/31 21:07
*/
HungrySingleton instance=HungrySingleton.getInstance();
//输出2个对象,并判断是否相等
System.out.println(newInstance);
System.out.println(instance);
System.out.println(newInstance==instance);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
二、静态内部类的反射攻击及解决方法
public class StaticInnerClassSingleton {
//私有的构造器,不被外部所访问
private StaticInnerClassSingleton(){
// 方式反射攻击
if(InnerClass.staticInnerClassSingleton !=null){
throw new RuntimeException("单例构造器进制反射调用");
}
// 方式反射攻击
}
//私有的静态内部类
private static class InnerClass{
//new一个私有的静态的StaticInnerClassSingleton对象
private static StaticInnerClassSingleton staticInnerClassSingleton=new StaticInnerClassSingleton();
}
//提供一个公用的对外暴露的方法
public static StaticInnerClassSingleton getInstance(){
//返回值为通过静态内部内调用静态成员
return InnerClass.staticInnerClassSingleton;
}
}
public static void main(String[] args) {
try {
/**
* @Description: 通过反射获取对象
* @Author: xz
* @Date: 2020/5/31 21:06
*/
//获取class对象
Class<StaticInnerClassSingleton> staticInnerClassSingletonClass = StaticInnerClassSingleton.class;
//通过获取的class对象,获取声明的构造器
Constructor<StaticInnerClassSingleton> declaredConstructor = staticInnerClassSingletonClass.getDeclaredConstructor();
//去除构造器的私有权限
declaredConstructor.setAccessible(true);
//通过构造器创建对象
StaticInnerClassSingleton newInstance = declaredConstructor.newInstance();
/**
* @Description: 直接通过类名.getInstance方法获取对象
* @Author: xz
* @Date: 2020/5/31 21:07
*/
StaticInnerClassSingleton instance=StaticInnerClassSingleton.getInstance();
//输出2个对象,并判断是否相等
System.out.println(newInstance);
System.out.println(instance);
System.out.println(newInstance==instance);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
三、懒汉式的反射攻击及解决方法
无法防止反射攻击
public class LazyDoubleCheckSingleton {
//声明一个需要被单例的对象,初始化时没有被创建所以设置null
/** volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。
* 而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。
* 这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
*/
private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;
private static boolean flag =true;
//私有的构造器,不被外部所访问
private LazyDoubleCheckSingleton(){
if(flag){
flag=false;
}else{
throw new RuntimeException("单例构造器进制反射调用");
}
}
//提供一个外部获取LazyDoubleCheckSingleton对象的静态方法
public static LazyDoubleCheckSingleton getInstance(){
if (lazyDoubleCheckSingleton==null){
synchronized (LazyDoubleCheckSingleton.class){
if(lazyDoubleCheckSingleton==null){
lazyDoubleCheckSingleton=new LazyDoubleCheckSingleton();
}
}
}
return lazyDoubleCheckSingleton;
}
}
public class LazyDoubleCheckTest {
public static void main(String[] args) {
try {
/**
* @Description: 通过反射获取对象
* @Author: xz
* @Date: 2020/5/31 21:06
*/
//获取class对象
Class<LazyDoubleCheckSingleton> lazySingletonClass = LazyDoubleCheckSingleton.class;
//通过获取的class对象,获取声明的构造器
Constructor<LazyDoubleCheckSingleton> declaredConstructor = lazySingletonClass.getDeclaredConstructor();
//去除构造器的私有权限
declaredConstructor.setAccessible(true);
/**
* @Description: 直接通过类名.getInstance方法获取对象
* @Author: xz
* @Date: 2020/5/31 21:07
*/
LazyDoubleCheckSingleton instance=LazyDoubleCheckSingleton.getInstance();
//修改懒汉式的私有属性
Field flag = instance.getClass().getDeclaredField("flag");
flag.setAccessible(true);
flag.set(instance,true);
//通过构造器创建对象
LazyDoubleCheckSingleton newInstance = declaredConstructor.newInstance();
//输出2个对象,并判断是否相等
System.out.println(newInstance);
System.out.println(instance);
System.out.println(newInstance==instance);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}