您的位置:首页 > 编程语言 > Java开发

关于Spring创建Bean的模式-Singleton(单例模式)和Prototype

2013-05-27 22:30 567 查看
Spring Bean的创建:默认情况下Spring中定义的Bean是以单例模式创建的。

在GoF中的单例模式是指一个ClassLoader中只存在类一个实例。

而在Spring中的单例实际上更确切的说应该是:

1.每个Spring Container中定义的Bean只存在一个实例

2.每个Bean定义只存在一个实例。

如果对Spring的单例模式不够了解在设计与开发过程中会留下很多隐患。以下是根据Spring中单例模式的特点写的测试代码,通过代码可以更直观的了解Spring中的单例模式。

以下main方法进行测试:

[java]

package beanscope;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopceMain

{

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

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="runnerBeanOne" class="beanscope.RunnerBeanRefToSingletonBean">

<property name="beanName" value="runnerBeanOne" />

<property name="singletonBean" ref="singletonBean" />

</bean> www.2cto.com

<bean id="runnerBeanTwo" class="beanscope.RunnerBeanRefToSingletonBeanTwo">

<property name="beanName" value="runnerBeanTwo" />

<!-- 这里更改了ref的值为singletonBeanTwo -->

<property name="singletonBean" ref="singletonBeanTwo" />

</bean>

<bean id="singletonBean" class="beanscope.SingletonBean">

<property name="lastOperatedBy">

<null />

</property>

</bean>

<!-- 增加了以下Bean定义 -->

<bean id="singletonBeanTwo" class="beanscope.SingletonBean">

<property name="lastOperatedBy">

<null />

</property>

</bean>

</beans>

更改配置文件后执行main方法类,输出:

none

runnerBeanOne

none

runnerBeanOne

runnerBeanOne

可以看出runnerBeanOne与runnerBeanTwo中引用的singletonBean已经不是同一个对象了,因为虽然都是SingletonBean类,

但是在配置文件中作出了两个Bean的定义,而Spring的单例模式只保证每个Bean的定义只存在一个实例。

接下来看前面说到的第一点,1.每个Spring Container中定义的Bean只存在一个实例。

使用改动之前的Spring配置文件,并更改main方法类如下:

package beanscope;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopceMain

{

public static void main(String[] args)

{

String springConfig = "beanscope/spring-config.xml";

//创建一个SpringContainer

ApplicationContext context = new ClassPathXmlApplicationContext(springConfig);

/****************************

* 创建另外一个SpringContainer

********/

ApplicationContext context2 = new ClassPathXmlApplicationContext(springConfig);

//通过SpringContainer取得runnerBeanOne

RunnerBeanRefToSingletonBean runnerBeanOne =

context.getBean("runnerBeanOne", RunnerBeanRefToSingletonBean.class);

/**************************************************

* 通过新创建的另外一个SpringContainer取得runnerBeanTwo

*****************/

RunnerBeanRefToSingletonBeanTwo runnerBeanTwo =

context2.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();

}

}

输出结果:

none

runnerBeanOne

none

runnerBeanOne

runnerBeanOne

在上边的代码中创建了两个SpringContainer对象 context 和 context2.分别用context和context2获取runnerBeanOne与runnerBeanTwo,

再进行操作与输出,从结果来看他们分别应用的singletonBean对象同样是两个不同的对象。虽然在配置文件中两个runnerBean都引用了

同一个singletonBean定义,但是因为是通过不同的SpringContainer创建的,所以仍然创建除了两个singletonBean对象这就可以理解

第一点:1.每个Spring Container中定义的Bean只存在一个实例。

Spring默认是以上述单例模式创建对象的,但是通过Bean标签中的设置scope="prototype"可以设置Spring不再以单例模式创建对象,

而是每次都创建新的对象。在上边的例子中,如果不再定义两个runnerBean,而是指定义一个runnerBean,但是给他设置属性scope=“prototype”,

那在main方法中就可以通过同一个context获取两个不同的runnerBean对象。但是需要注意的是,因为runnerBean引用的singletonBean没有被设置为prototype,

所以虽然创建除了两个不同的runnerBean对象,但他们所引用的singletonBean仍然是同一个。

<bean id="runnerBeanOne" class="beanscope.RunnerBeanRefToSingletonBean"

scope="prototype">

<property name="beanName" value="runnerBeanOne" />

<property name="singletonBean" ref="singletonBean" />

</bean>

<bean id="singletonBean" class="beanscope.SingletonBean">

<property name="lastOperatedBy">

<null />

</property>

</bean>

所以单例模式在Spring中的使用需要额外的注意。

所有代码:

package beanscope;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BeanScopceMain

{

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();

}

}

SingletonBean类:

package beanscope;

public class SingletonBean

{

// 用来保存上次操作此Bean的对象

private String lastOperatedBy;

public String getLastOperatedBy()

{

return lastOperatedBy;

}

public void setLastOperatedBy(String lastOperatedBy)

{

this.lastOperatedBy = lastOperatedBy;

}

public void showLastOperateBean()

{

if(lastOperatedBy!=null)

System.out.println(lastOperatedBy);

else

System.out.println("none");

}

}

RunnerBeanRefToSingletonBean类:

package beanscope;

public class RunnerBeanRefToSingletonBean

{

private String beanName;

private SingletonBean singletonBean;

public String getBeanName()

{

return beanName;

}

public void setBeanName(String beanName)

{

this.beanName = beanName;

}

public SingletonBean getSingletonBean()

{

return singletonBean;

}

public void setSingletonBean(SingletonBean singletonBean)

{

this.singletonBean = singletonBean;

}

public void setMyNameToSingletonBean()

{

singletonBean.setLastOperatedBy(beanName);

}

public void showLastOprBeanOfSingletonBean()

{

singletonBean.showLastOperateBean();

}

}

RunnerBeanRefToSingletonBeanTwo类:

[java]

package beanscope;

public class RunnerBeanRefToSingletonBeanTwo

{

private String beanName;

private SingletonBean singletonBean;

public String getBeanName()

{

return beanName;

}

public void setBeanName(String beanName)

{

this.beanName = beanName;

}

public SingletonBean getSingletonBean()

{

return singletonBean;

}

public void setSingletonBean(SingletonBean singletonBean)

{

this.singletonBean = singletonBean;

}

public void setMyNameToSingletonBean()

{

singletonBean.setLastOperatedBy(beanName);

}

public void showLastOprBeanOfSingletonBean()

{

singletonBean.showLastOperateBean();

}

}

spring-config.xml

[html]

<?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

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

<bean id="runnerBeanOne" class="beanscope.RunnerBeanRefToSingletonBean">

<property name="beanName" value="runnerBeanOne" />

<property name="singletonBean" ref="singletonBean" />

</bean>

<bean id="runnerBeanTwo" class="beanscope.RunnerBeanRefToSingletonBeanTwo">

<property name="beanName" value="runnerBeanTwo" />

<property name="singletonBean" ref="singletonBean" />

</bean>

<bean id="singletonBean" class="beanscope.SingletonBean">

<property name="lastOperatedBy">

<null />

</property>

</bean>

</beans>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: