刚开始接触Spring的时候一些基础的教学在说到Bean的创建时会提到Spring的单例模式,就是说默认情况下Spring中定义的Bean是以单例模式创建的。如果以前了解设计模式中的单例模式的话很容易对这种说法产生先入为主的印象。事实上,Spring中的单例模式还有许多需要注意的地方。
在GoF中的单例模式是指一个ClassLoader中只存在类一个实例。
而在Spring中的单例实际上更确切的说应该是:
1.每个Spring Container中定义的Bean只存在一个实例
2.每个Bean定义只存在一个实例。
如果对Spring的单例模式不够了解在设计与开发过程中会留下很多隐患。以下是根据Spring中单例模式的特点写的测试代码,通过代码可以更直观的了解Spring中的单例模式。
先看一下这个测试中用到的类已经XML中Bean的定义.随后给出Main方法中的测试代码:
根据以上类定义,执行以下main方法进行测试:
- package beanscope;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class BeanScopceMain
- {
- /**
- * @comment [注释说明]
- * @author 荣磊, 2012-7-17
- *
- * @param args
- */
- public static void main(String[] args)
- {
- String springConfig = "beanscope/spring-config.xml";
- //创建一个SpringContainer
- ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
- //通过SpringContainer取得runnerBeanOne
- RunnerBeanRefToSingletonBean runnerBeanOne =
- context.getBean("runnerBeanOne", RunnerBeanRefToSingletonBean.class);
- //通过SpringContainer取得runnerBeanTwo
- RunnerBeanRefToSingletonBeanTwo runnerBeanTwo =
- context.getBean("runnerBeanTwo", RunnerBeanRefToSingletonBeanTwo.class);
- //通过SpringContainer取得singletonBean
- SingletonBean singletonBean =
- context.getBean("singletonBean", SingletonBean.class);
- //输出上一次操作singltonBean的Bean名称,
- //因为在这之前没有对singletonBean的lastOperatedBy属性进行初始化,所以这里应该会输出none
- singletonBean.showLastOperateBean();
- //设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanOne
- runnerBeanOne.setMyNameToSingletonBean();
- //通过singletonBean输出上一次操作者信息
- singletonBean.showLastOperateBean();
- //输出runnerBeanTwo中应用的singletonBean对象的上一次操作者信息
- runnerBeanTwo.showLastOprBeanOfSingletonBean();
- //设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanTwo
- runnerBeanTwo.setMyNameToSingletonBean();
- //通过singletonBean输出上一次操作者信息
- singletonBean.showLastOperateBean();
- //输出runnerBeanOne中应用的singletonBean对象的上一次操作者信息
- runnerBeanOne.showLastOprBeanOfSingletonBean();
- }
- }
package beanscope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanScopceMain
{
/**
* @comment [注释说明]
* @author 荣磊, 2012-7-17
*
* @param args
*/
public static void main(String[] args)
{
String springConfig = "beanscope/spring-config.xml";
//创建一个SpringContainer
ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);
//通过SpringContainer取得runnerBeanOne
RunnerBeanRefToSingletonBean runnerBeanOne =
context.getBean("runnerBeanOne", RunnerBeanRefToSingletonBean.class);
//通过SpringContainer取得runnerBeanTwo
RunnerBeanRefToSingletonBeanTwo runnerBeanTwo =
context.getBean("runnerBeanTwo", RunnerBeanRefToSingletonBeanTwo.class);
//通过SpringContainer取得singletonBean
SingletonBean singletonBean =
context.getBean("singletonBean", SingletonBean.class);
//输出上一次操作singltonBean的Bean名称,
//因为在这之前没有对singletonBean的lastOperatedBy属性进行初始化,所以这里应该会输出none
singletonBean.showLastOperateBean();
//设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanOne
runnerBeanOne.setMyNameToSingletonBean();
//通过singletonBean输出上一次操作者信息
singletonBean.showLastOperateBean();
//输出runnerBeanTwo中应用的singletonBean对象的上一次操作者信息
runnerBeanTwo.showLastOprBeanOfSingletonBean();
//设置runnerBeanOne中singletonBean对象的上一次操作者信息为runnerBeanTwo
runnerBeanTwo.setMyNameToSingletonBean();
//通过singletonBean输出上一次操作者信息
singletonBean.showLastOperateBean();
//输出runnerBeanOne中应用的singletonBean对象的上一次操作者信息
runnerBeanOne.showLastOprBeanOfSingletonBean();
}
}
输出结果:
从这个执行结果来看已经可以看出单例模式的影子,两个分别创建的runnerBean对象在定义中都依赖于singletonBean对象,第2步中,使用runnerBeanOne.setMyNameToSingletonBean()方法,设置了runnerBeanOne自己引用的singletonBean的操作者信息,随后输出了runnerBeanTwo自己引用的singletonBean和单独创建的singletonBean的操作者信息,结果都是runnerBeanOne,这就说明,当runnerBeanOne操作自己引用的singletonBean时,对runnerBeanTwo中和单独创建的singletonBean产生了影响,也就是他们所引用的singletonBean对象是同一个对象。
这是因为runnerBeanOne与runnerBeanTwo在Spring定义Bean时都设置了一个property ref引用到了同一个singletonBean的Bean定义。 这就是最前面说道的两点中的第二点:2.每个Bean定义只存在一个实例。 如果在Spring配置文件中定义runnerBeanOne与runnerBeanTwo时引用到不同的singletonBean定义,就会创建出两个不同的singletonBean对象,即使两个Bean定义实际上对应的class是相同的。如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans