spring怎么实现单例模式?
Spring学习之路——单例模式和多例模式
在Spring中,bean可以被定义为两种模式:prototype(多例)和singleton(单例)
singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。
prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new。
Spring bean 默认是单例模式。
实战演示:
代码详见上一篇文章中的代码。
在配置文件中,修改这句代码为:
1 <bean id="hi" class="com.test.Hi" init-method="init" scope="singleton">
在测试类中,修改代码为:
1 ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml");
2 Hi hi1 = (Hi) context.getBean("hi");
3 Hi hi2 = (Hi) context.getBean("hi");
4 System.out.println(hi1);
5 System.out.println(hi2);
结果为:

结论:二个变量指向一个对象。
将配置文件改为:
<bean id="hi" class="com.test.Hi" init-method="init" scope="prototype">
其他的不变,运行测试类,结果为:

结论:每次访问bean,均创建一个新实例。
单例模式有以下的特点:
①
单例类只能有一个实例
②
单例类必须自己创建自己的唯一实例
③
单例类必须给所有其他对象提供这一实例
下面我们就来写一个简单的单例模式的例子:
Public class Singleton1{
Private static final Singleton1 instance=new Singleton1();
//私有的默认构造函数
Public Singleton1(){}
//静态工厂方法
Public static Singleton1 getInstance(){
Return instance;
}
}
大家可以看出来,在这个类被加载时,静态变量instance会被初始化,此时该类的私有构造函数被调用,这时候,单例类的唯一实例就被创建出来了
值得注意的是:由于构造函数是私有的,因此该类不能被继承
还有一种写法也可以实现单例模式:
Public class Singleton2{
Private static final Singleton2 instance=null;
//私有的默认构造函数
Public Singleton1(){}
//静态工厂方法
Public synchronized static Singleton2 getInstance(){
If(instance==null){
Instance=new Singleton2();
}
Return instance;
}
}
这种写法和第一种的区别在于:实例并没有直接实例化,而是在静态工厂方法被调用的时候才进行的,而且对静态工厂方法使用了同步化,以处理多线程并发的环境。
这两种写法还有两个非常有意思的名字:第一种称为饿汉式单例,第二种称为懒汉式单例。至于为什么起这个名字,自己好好想想吧。
饿汉式单例在自己被加载时就将自己实例化,如果从资源利用效率角度来讲,比懒汉式单例类稍差些。但是从速度和反应时间角度来讲,则比懒汉式要稍好些。
但是遗憾的是:懒汉式单例类也不能被继承。
我们克服前两种单例类不能被继承的缺点,我们可以使用另外一种特殊化的单例模式,它被称为单例注册表。
Import java.util.HashMap;
Public class RegSingleton{
Static private HashMap registry=new HashMap();
//静态块,在类被加载时自动执行
Static{
RegSingleton rs=new RegSingleton();
Registry.put(rs.getClass().getName(),rs);
}
//受保护的默认构造函数,如果为继承关系,则可以调用,克服了单例类不能为继承的缺点
Protected RegSingleton(){}
//静态工厂方法,返回此类的唯一实例
public static RegSingleton getInstance(String name){
if(name==null){
name=” RegSingleton”;
}if(registry.get(name)==null){
try{
registry.put(name,Class.forName(name).newInstance());
}Catch(Exception ex){ex.printStackTrace();}
}
Return (RegSingleton)registry.get(name);
}
}
| <bean id="date" class="java.util.Date"/> |
| <bean id="date" class="java.util.Date" scope="singleton"/> (仅为Spring2.0支持) |
| <bean id="date" class="java.util.Date" singleton="true"/> |
| <bean id="date" class="java.util.Date" scope="prototype"/> |
那么Spring对单例的底层实现,到底是饿汉式单例还是懒汉式单例呢?呵呵,都不是。Spring框架对单例的支持是采用单例注册表的方式进行实现的,源码如下:
public abstract class AbstractBeanFactory implements ConfigurableBeanFactory{
/**
* 充当了Bean实例的缓存,实现方式和单例注册表相同
*/
private final Map singletonCache=new HashMap();
public Object getBean(String name)throws BeansException{
return getBean(name,null,null);
}
...
public Object getBean(String name,Class requiredType,Object[] args)throws BeansException{
//对传入的Bean name稍做处理,防止传入的Bean name名有非法字符(或则做转码)
String beanName=transformedBeanName(name);
Object bean=null;
//手工检测单例注册表
Object sharedInstance=null;
//使用了代码锁定同步块,原理和同步方法相似,但是这种写法效率更高
synchronized(this.singletonCache){
sharedInstance=this.singletonCache.get(beanName);
}
if(sharedInstance!=null){
...
//返回合适的缓存Bean实例
bean=getObjectForSharedInstance(name,sharedInstance);
}else{
...
//取得Bean的定义
RootBeanDefinition mergedBeanDefinition=getMergedBeanDefinition(beanName,false);
...
//根据Bean定义判断,此判断依据通常来自于组件配置文件的单例属性开关
//<bean id="date" class="java.util.Date" scope="singleton"/>
//如果是单例,做如下处理
if(mergedBeanDefinition.isSingleton()){
synchronized(this.singletonCache){
//再次检测单例注册表
sharedInstance=this.singletonCache.get(beanName);
if(sharedInstance==null){
...
try {
//真正创建Bean实例
sharedInstance=createBean(beanName,mergedBeanDefinition,args);
//向单例注册表注册Bean实例
addSingleton(beanName,sharedInstance);
}catch (Exception ex) {
...
}finally{
...
}
}
}
bean=getObjectForSharedInstance(name,sharedInstance);
}
//如果是非单例,即prototpye,每次都要新创建一个Bean实例
//<bean id="date" class="java.util.Date" scope="prototype"/>
else{
bean=createBean(beanName,mergedBeanDefinition,args);
}
}
...
return bean;
}
}
spring怎么实现单例模式?的更多相关文章
- Spring中的单例模式
Spring中的单例模式 单例模式的介绍 1.1 简介 保证整个应用中某个实例有且只有一个 1.2作用 保证一个类仅有一个实例,并且提供一个访问它的全局访问点. 单例模式的优点和缺点 单例模式的优 ...
- spring默认为单例模式
这两天看到一个bug,记录下. 在获取任务的时候,本来任务不是由这个柜员领取的,但是最后跑到那个柜员下面去了. 查看日志,发现两个任务的领取操作很近,日志是穿插着打的. 后来经人指点,说spring初 ...
- Spring中的单例模式和多例模式的应用
在Spring的配置中,Bean的scope属性中存在两种模式:singleton(单例模式).prototype(多例模式) singleton 单例模式:对象在整个系统中只有一份,所有的请求都用一 ...
- (转)Spring的单例模式底层实现
单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例. 单例模式有以下的特点: ① 单例类只能有一个实例 ② 单例类必须自己创建自己的唯一实例 ③ 单例类 ...
- Spring bean默认为单例模式会引发并发问题吗
在web项目中使用spring,如果网站同时很多人访问,这时候使用spring默认的单例模式的bean是否合适呢?回不回影响效率或者产生交叉呢? Spring默认的单例模式的bean,因为是单例的,所 ...
- Spring的单例模式底层实现学习笔记
单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例.单例模式有以下的特点:①单例类只能有一个实例②单例类必须自己创建自己的唯一实例③单例类必须给所有其他 ...
- 【Java EE 学习 49 上】【Spring学习第一天】【基本配置】
一.HelloWorld 需要的jar文件(以2.5.5为例):spring.jar,common-logging.jar 1.新建类com.kdyzm.spring.helloworld.Hello ...
- Spring 使用中的设计模式
1. 简单工厂 又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一. 简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类. ...
- Spring中的设计模式学习
Spring提供了一种Template的设计哲学,包含了很多优秀的软件工程思想. 1. 简单工厂 又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一. ...
随机推荐
- 20145214 《Java程序设计》第2周学习总结
20145214 <Java程序设计>第2周学习总结 教材学习内容总结 基本类型 整数:可分为short整数.int整数.long整数. 字节:即byte类型,可表示-128~127的整数 ...
- iOS开发Interface Builder技巧
1.使view的Size与view中的Content相适应:选中任意的一个view,然后Editor->Size to Fit Content,或者简单的按 ⌘=接着就会按照下面的规则对选中vi ...
- 父类属性值的copy
最近开发中遇到这样一个问题将父类的属性值copy到子类中,从而对子类添加一些其他属性. 父类: package com.jalja.org.jms.test01; import java.util.D ...
- [剑指Offer] 63.数据流中的中位数
题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. c ...
- C# Directory.GetFiles()获取文件时如果是根目录时有隐藏文件则报错的处理
如果Directory.GetFiles("d:\"),则由于回收站是隐藏文件而报错,怎么躲避这种错误呢, 我要了一种办法,只要遇到隐藏文件夹就跳过的方法: foreach (va ...
- canvas画布上定位点击位置
两种方法: 1. cvs.onclick = function (e) { if (e.offsetX || e.layerX) { var x = e.offsetX == undefined ? ...
- 【bzoj2318】Spoj4060 game with probability Problem 概率dp
题目描述 Alice和Bob在玩一个游戏.有n个石子在这里,Alice和Bob轮流投掷硬币,如果正面朝上,则从n个石子中取出一个石子,否则不做任何事.取到最后一颗石子的人胜利.Alice在投掷硬币时有 ...
- BZOJ4767 两双手(组合数学+容斥原理)
因为保证了两向量不共线,平面内任何一个向量都被这两个向量唯一表示.问题变为一张有障碍点的网格图由左上走到右下的方案数. 到达终点所需步数显然是平方级别的,没法直接递推.注意到障碍点数量很少,那么考虑容 ...
- BZOJ4897 THUSC2016成绩单(区间dp)
拿走一个区间的代价只与最大最小值有关,并且如果最后一次拿走包含区间右端点的子序列一定不会使答案更劣,于是设f[i][j][x][y]为使i~j区间剩余最小值为x最大值为y且若有数剩余一定包含j的最小代 ...
- BZOJ3709 [PA2014]Bohater 【贪心】
题目链接 BZOJ3709 题解 贪心很显然 我们先干掉能回血的怪,当然按照\(d\)升序顺序,因为打得越多血越多,\(d\)大的尽量往后打 然后再干掉会扣血的怪,当然按照\(a\)降序顺序,因为最后 ...