Spring2.5学习1.4_bean的作用域及其实例化时期
由于目前的工程是纯java工程,只对前两种域进行代码演示,后面三中会在以后的web项目中进行详解。
Spring Framework支持五种作用域(其中有三种只能用在基于web的Spring ApplicationContext)。
1、singleton:当一个bean的作用域为singleton, 那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。bean是在Spring容器初始化的过程中生成的,ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
注意:Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:
<bean id="empServiceImpl" class="cn.csdn.service.EmpServiceImpl" scope="singleton">
2、prototype:一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。bean是在调用getBean("personService");方法时生成的,这个也不难理解,如果不调用getBean()方法,容器怎么知道应该对那个bean进行实例化呢?
以下是相关代码片段及其运行结果
1.bean的作用域在默认状态下是singleton类型
bean配置(缺省,或者scope="singleton"):
<bean id="personService" class="xjj.service.impl.PersonServiceBean"></bean>SpringTest2
package junit.test; import org.junit.BeforeClass; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import xjj.service.PersonService; public class SpringTest2 { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void instanceSpring(){ ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService = (PersonService)ctx.getBean("personService"); PersonService personService2 = (PersonService)ctx.getBean("personService"); System.out.println(personService==personService2); } }结果:返回结果是true,证明两次获取的bean是同一个实例。
2.bean的作用域是prototype
bean配置:
<bean id="personService" class="xjj.service.impl.PersonServiceBean" scope="prototype"></bean>SptingTest2文件类容同上
结果:返回结果的false,说明两次获取的是不同的bean实例。
3.bean的实例化时期
PersonServiceBean.java类
package xjj.service.impl; import xjj.service.PersonService; public class PersonServiceBean implements PersonService { public void init(){ System.out.println("初始化"); } public PersonServiceBean() { System.out.println("我被实例化了"); } public void save() { System.out.println("我是save()方法"); } public void destory() { System.out.println("开闭打开的资源"); } }bean配置中可以通过更改scope属性,设置不同域
SpringTest2可以通过注掉第二行代码,根据是否执行构造方法PersonServiceBean()来判断实例化时期
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService1 = (PersonService)ctx.getBean("personService");结果:scope="prototype",在注释掉第二行代码是,没有输出,然后再恢复第二行代码
4.当作用域是singleton时,可以在bean中添加lazy-init="true"属性,对bean的实例化时期进行延时,使其在调用getBean()方法时实例化,
如果想让所有singleton域的bean都延时初始化,可以在其父节点beans添加属性default-lazy-init="true"
5.在实例化bean之后立即进行某些操作(比如链接数据库),可以在bean中添加init-method="方法名",例如想执行PersonServiceBean中的init方法
bean配置:
<bean id="personService" class="xjj.service.impl.PersonServiceBean" init-method="init"</bean>结果:先实例化bean,再执行初始化方法
6.bean使用完以后,正常销毁bean,添加属性: destroy-method="destory"
bean配置:
<bean id="personService" class="xjj.service.impl.PersonServiceBean" init-method="init"destroy-method="destory"</bean>SpringTest2,通过引用抽象类AbstractApplicationContext,调用close方法,关闭资源
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); ctx.close();结果:
另外三种作用域介绍:
3、request:在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例, 它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。
考虑下面bean定义:
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
针对每次HTTP请求,Spring容器会根据loginAction bean定义创建一个全新的LoginAction bean实例, 且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态, 而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。 当处理请求结束,request作用域的bean实例将被销毁。
4、session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
考虑下面bean定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例, 且该userPreferences bean仅在当前HTTP Session内有效。 与request作用域一样,你可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例, 将不会看到这些特定于某个HTTP Session的状态变化。 当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。
5、global session:在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。
考虑下面bean定义:
<bean id="userPreferences" class="com.foo.UserPreferences" scope="globalSession"/>
global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。
请注意:假如你在编写一个标准的基于Servlet的web应用,并且定义了一个或多个具有global session作用域的bean,系统会使用标准的HTTP Session作用域,并且不会引起任何错误。