单例模式的终结者——setAccessible(true)

先来看下“传统”的单例模式

package go.derek;

public class Singleton{

	public static int times;
	private Singleton(){
		//构造器被调用的时候会打印出次数
		System.out.println("单例构造器被调用"+(++times)+"两次");
	}

	private final static Singleton instance=new Singleton();

	public static Singleton getInstance(){
		return instance;
	}

	public void doSomething(){
		System.out.println("do something");
	}

}

下面是测试类主函数:

package go.derek;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Test {
	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//通过单例模式获得单例对象obj1
		Singleton obj1=Singleton.getInstance();
		//执行一次doSomething方法
		obj1.doSomething();
		//观察控制台,这次获得的obj2对象跟obj1是同一个单例,没有调用构造器
		Singleton obj2=Singleton.getInstance();
		obj2.doSomething();
		//下面厉害的来了,首先拿到万能的Class对象
		Class<Singleton> clazz=Singleton.class;
		//然后拿到构造器,使用这个方法私有的构造器也可以拿到
		Constructor<Singleton> c=clazz.getDeclaredConstructor();
		//设置在使用构造器的时候不执行权限检查
		c.setAccessible(true);
		//由于没有了权限检查,所以在Singleton类外面也可以创建对象了,然后执行方法
		//观察控制台,私有构造器又被调用了一次,单例模式被攻陷了,执行方法成功。
		c.newInstance().doSomething();
	}
}

运行结果如下:

单例构造器被调用1两次

do something

do something

单例构造器被调用2两次

do something

试想一下,如果某个恶意客户端通过上面的方式,就可以为所欲为了,所以为了避免出现这种情况,可以再构造器被第二次调用的时候抛出一个异常

package go.derek;

public class Singleton{

	public static int times;
	private Singleton() {
		//构造器被调用的时候会打印出次数
		System.out.println("单例构造器被调用"+(++times)+"两次");
		if(instance!=null){
			throw new IllegalArgumentException("单例构造器不能重复使用");
		}
	}

	private final static Singleton instance=new Singleton();

	public static Singleton getInstance(){
		return instance;
	}

	public void doSomething(){
		System.out.println("do something");
	}

}

运行结果如下:

单例构造器被调用1两次

do something

do something

单例构造器被调用2两次

Exception in thread "main" java.lang.reflect.InvocationTargetException

at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

at java.lang.reflect.Constructor.newInstance(Constructor.java:526)

at go.derek.Test.main(Test.java:24)

Caused by: java.lang.IllegalArgumentException: 单例构造器不能重复使用

at go.derek.Singleton.<init>(Singleton.java:10)

... 5 more

目的达到了~

时间: 2024-08-15 02:15:32

单例模式的终结者——setAccessible(true)的相关文章

Java 反射 getDeclareFields getModifiers setAccessible(true)

示例代码: public static Map<String, Object> dtoToMap(Object obj, String pre,            String las) {        Map result = new HashMap();        Class clazz = obj.getClass();        Field[] fs = clazz.getDeclaredFields();        for (int i = 0; i < fs

使用单元素枚举类实现单例模式

在上一篇文章<单例模式的终结者--setAccessible(true)>中介绍了传统单例模式的不足之处,虽然枚举类实现单例模式还没有被广泛采用,但<effective java>里面已经承认单元素枚举类是实现单例模式最好的方法了. 下面写个小demo示范一下,这是只有一个元素的枚举类,枚举类里面也可以写方法. package go.derek; public enum EnumSingleton { instance; public void doSomething(){ Sys

Java设计模式学习笔记,一:单例模式

开始学习Java的设计模式,因为做了很多年C语言,所以语言基础的学习很快,但是面向过程向面向对象的编程思想的转变还是需要耗费很多的代码量的.所有希望通过设计模式的学习,能更深入的学习. 把学习过程中的笔记,记录下来,只记干货. 第一部分:单例模式的内容 单例模式:类只能有一个实例. 类的特点:1.私有构造器:2.内部构造实例对象:3.对外提供获取唯一实例的public方法. 常见的单例模式实现有五种形式: 1.饿汉式. 2.懒汉式. 3.双重检查锁式. 4.静态内部类式. 5.枚举式. 以下分别

设计模式(一)单例模式

单例模式:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. 优点:1. 由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置.产生其他依赖对象时,则可以通过在应用启动时产生一个单例对象,然后永久驻留内存的方式来解决. 2. 单例模式可以在系统设置全局的访问点,例如可以设计一个单例类,负责所有数据表的映射处理. 常见的五种单例模式实现方式: 饿汉式:线程安全,调用效率高.但是,不能延时加载. 懒汉式:线程安全,调用效率不高.但是,可以延时加载.

单例模式--反射--防止序列化破坏单例模式

本文牵涉到的概念: 1.单例模式------唯一最佳实现方式,使用枚举类实现 2.单例模式的几种实现,各自的缺点 3.反射;反射是如何破坏单例模式 4.序列化:序列化如何破坏单例模式 单例模式 单例模式,是指在任何时候,该类只能被实例化一次,在任何时候,访问该类的对象,对象都是同一的,只有一个. 单例模式的实现方式: a.使用类公有的静态成员来保存该唯一对象 public class EagerSingleton { // jvm保证在任何线程访问uniqueInstance静态变量之前一定先创

单例模式破解之反射和反序列化

5种单例模式中除了枚举式,其他都存在反射和反序列化的漏洞,下面来讲述一下: 下面是破解代码: /** * * 描述:测试反射和反序列化破解单例模式Demo06 * @author cookie */ public class Client { public static void main(String[] args) throws Exception { SingletonDemo06 s1 = SingletonDemo06.getInstance(); SingletonDemo06 s2

设计模式之第0章-单例模式

设计模式之第0章-单例模式 当当当当~首先有请最简单的单例模式登场,先来个自我介绍吧 单例模式之自我介绍 我,单例模式(Singleton Pattern)是一个比较简单的模式,我的定义如下: Ensure a class has only one instance,and provide a global point of access to it.(确保其某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.)单例模式的通用类图如下: Singleton类称为单例类,通过使用priv

23种设计模式(1):单例模式

转:http://blog.csdn.net/zhengzhb/article/details/7331369 ———————————————————————————————————————— 定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例. 类型:创建类模式 类图: 类图知识点: 1.类图分为三部分,依次是类名.属性.方法 2.以<<开头和以>>结尾的为注释信息 3.修饰符+代表public,-代表private,#代表protected,什么都没有代表包可

单例模式不是一件小事,快回来看看

上次写了一篇<单例模式那件小事,看了你不会后悔>的文章,总结了常用的单例模式的实现.本文是上文的延续,单例模式绝不是一件小事,想弄清楚,真不是那么简单的.上文提到了常用的三种单例模式的实现方法:饿汉式(除了提前占用资源,没毛病.),懒汉式(DCL优化过后,没毛病?),静态内部类式(优雅的方法,没毛病.).文末最后还提到,反射会破坏单例. 本文继续,双重检查锁定优化过后的懒汉式,真的没毛病吗?其实不是,这里涉及到java编译器编译时的一些细节,对象初始化时的写操作与写入 sSingleton 字