一、知识点
当你在配置文件中声明Bean时,实际上定义了Bean创建的一个模板,而不是真正的Bean实例。当getBean()方法或者其它Bean的引用请求Bean时,Spring将根据Bean作用域(Scope)决定该返回哪个Bean实例。有时候必须为Bean设置正确的作用域而不是使用默认的(singleton)作用域。
在Spring2.x或更高版本中,Bean的作用域在<bean>元素的scope属性中设置。默认情况下,Spring为IoC容器中声明的每个Bean创建一个实例,这个实例将在整个IoC容器的范围内共享。所有后续的getBean()调用和bean引用都将返回这个唯一的bean实例。这种作用域称作singleton,是所有Bean的默认作用域。下面是Spring中所有有效的Bean作用域。
Singleton:每个Spring IoC容器创建单个bean实例。
Prototype:每次请求时创建一个新的Bean实例。
Request:每个HTTP请求创建一个Bean实例,仅在Web应用上下文中有效。
Session:每个HTTP会话创建一个Bean实例,仅在Web应用上下文中有效。
GlobalSession:为每个全局HTTP会话创建一个Bean实例,仅在portal应用上下文中有效。
二、代码示例
创建ShoppingCart类
package com.jackie.codeproject.springrecipesnote.springadvancedioc; import java.util.ArrayList; import java.util.List; public class ShoppingCart { private List<Product> items = new ArrayList<Product>(); public void addItem(Product item) { items.add(item); } public List<Product> getItems() { return items; } }
Bean配置
<?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.2.xsd"> <bean id="aaa" class="com.jackie.codeproject.springrecipesnote.springadvancedioc.Battery"> <property name="name" value="AAA" /> <property name="price" value="2.5" /> </bean> <bean id="cdrw" class="com.jackie.codeproject.springrecipesnote.springadvancedioc.Battery"> <property name="name" value="CD-RW" /> <property name="price" value="1.5" /> </bean> <bean id="dvdrw" class="com.jackie.codeproject.springrecipesnote.springadvancedioc.Battery"> <property name="name" value="DVD-RW" /> <property name="price" value="3.0" /> </bean> <bean id="shoppingCart" class="com.jackie.codeproject.springrecipesnote.springadvancedioc.ShoppingCart" /> </beans>
测试类
package com.jackie.codeproject.springrecipesnote.springadvancedioc; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BeanScopeTest { private ApplicationContext applicationContext; @Test public void testBeanScope(){ applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); Product aaa = (Product) applicationContext.getBean("aaa"); Product cdrw = (Product) applicationContext.getBean("cdrw"); Product dvdrw = (Product) applicationContext.getBean("dvdrw"); ShoppingCart shoppingCart1 = (ShoppingCart) applicationContext.getBean("shoppingCart"); shoppingCart1.addItem(aaa); shoppingCart1.addItem(cdrw); System.out.println("Shopping cart 1 contains " + shoppingCart1.getItems()); ShoppingCart cart2 = (ShoppingCart) applicationContext.getBean("shoppingCart"); cart2.addItem(dvdrw); System.out.println("Shopping cart 2 contains " + cart2.getItems()); } }
运行结果如下:
Shopping cart 1 contains [AAA:2.5, CD-RW:1.5] Shopping cart 2 contains [AAA:2.5, CD-RW:1.5, DVD-RW:3.0]
可以看到两个取得的是同一个购物车实例,这是因为Spring默认的Bean作用域是singleton,意味着Spring为每个IoC容器创建一个购物车实例:
<bean id="shoppingCart" class="com.jackie.codeproject.springrecipesnote.springadvancedioc.ShoppingCart" scope="singleton" />
如果你期望每位顾客调用getBean()方法时获得不同的购物车实例,可以将shoppingCart这个Bean的scope属性改为prototype。之后Spring将为每个getBean()方法调用和其它Bean中的引用创建一个新的Bean实例。
<bean id="shoppingCart" class="com.jackie.codeproject.springrecipesnote.springadvancedioc.ShoppingCart" scope="prototype" />
再次运行测试类,结果如下:
Shopping cart 1 contains [AAA:2.5, CD-RW:1.5] Shopping cart 2 contains [DVD-RW:3.0]