一、前言
Singleton 模式主要作用是保证Java程序中,一个类Class只有一个实例存在,例如在数据中连接,全局计数器。另外Singleton也有能够无状态化,提供工具的性质功能。
二、两种形式
1、
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例,是不是很奇怪?
//注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
2、
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
//使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance; }
}
三、在spring 中的应用
问题如下:如果一个singleton的Bean依赖于一个prototype的Bean,如何让这个singleton的Bean每次获得最新的prototype类型的Bean?
当Spring容器中作用域不同的Bean相互依赖时,可能出现一些问题,例如:一个作用域为Singleton的Bean(设为A)依赖于一个作用域为prototype的Bean(设为B)。由于A是单例的,只有一次初始化的机会,它的依赖关系也只在初始化阶段被设置,但它所依赖的B每次都会创建一个全新的实例,这将使A中的B不能及时得到更新。这样将导致如果客户端多次请求A,并调用A中B的某个方法(或获取A中B的某个属性),服务端总是返回同一个B,但客户端直接请求B却能获得最新的对象,这就产生了对象不同步的情况。这样就违背了B初衷:本来希望B具有prototype的行为,但是却表现出singleton的行为了。那么,问题如何解决呢?
办法有二:
-
部分放弃依赖注入:当A每次需要B时,主动向容器请求新的Bean实例,即可保证每次注入的B都是最新的实例。
-
利用方法注入。
第一种方式显然不是一个好的做法,代码主动请求Bean实例,必然导致代码与SpringAPI耦合在一起,造成严重的代码污染。通常情况下,我们会采用第二种做法。使用方法注入。
方法注入通常使用lookup方法注入,利用lookup方法注入可以让Spring容器重写容器中Bean的抽象或具体方法,返回查找容器中其他Bean的结果,被查找的Bean通常是一个non-singleton的Bean(尽管也可以是一个singleton的Bean)。Spring通过使用CGLIB库修改客户端的二进制码,从而实现上述要求。看下面的例子:
1
2
3
4
5
6
7
8
|
public
class
CellPhone
implements
Phone {
public
CellPhone() {
System.out.println(
"Spring实例化依赖的Bean...CellPhone实例"
);
}
public
return
call() {
return
"正在打电话..."
;
}
}
|
上面的CellPhone将被部署成prototype的Bean,并被一个singleton的Bean所依赖。如果让Spring容器直接将prototype的Bean注入到singleton中,就会出现上面的问题。为了解决这个问题