在配置文件里声明的Bean时,实际定义的并不是一个Bean实例,而是为Bean创建了一个模板,当通过getBean()调用或其他请求改Bean的时候,Spring将根据Bean的实际作用域返回Bean的实例,在某些情况下默认的作用域并不适合,此时需要为Bean设置一个更适合的作用域。
在Spring2.x里,可以通过<bean>中的scope属性设置作用域,默认情况下Spring只为在Ioc容器里声明的Bean创建一个实例,整个Ioc范围内都共享这个实例,所有后续的getBean()调用和引用该实例,都将返回这个唯一的Bean实例。这个作用域称为singleton,是默认的作用域。
Spring2.x中Bean的几种作用域:
1、singleton--------------为每个Spring Ioc容器创建一个Bean实例;
2、prototype-------------每次请求时都创建一个新的实例;
3、request---------------每个HTTP请求创建一个Bean实例,这个作用域仅在WEB应用程序的上下文中有效;
4、session---------------每个HTTP请求创建一个Bean实例,这个作用域仅在WEB应用程序的上下文中有效;
5、globalSession------为每个全局的HTTP会话创建一个Bean实例,这个作用域尽在门户应用程序的上下文中有效;
下边将用一个商品购物车例子来说明这个Bean的实例作用域:
package com.song.spring.scope; public abstract class Product { private String name; private double price; public Product(){} public Product(String name, double price){ this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String toString(){ return name + " " + price; } }
package com.song.spring.scope; public class Battery extends Product { private boolean rechargeable; public Battery(){ super(); } public Battery(String name, double price){ super(name, price); } public boolean isRechargeable() { return rechargeable; } public void setRechargeable(boolean rechargeable) { this.rechargeable = rechargeable; } }
package com.song.spring.scope; public class Disc extends Product { private int capacity; public Disc(){ super(); } public Disc(String name, double price){ super(name, price); } public int getCapacity() { return capacity; } public void setCapacity(int capacity) { this.capacity = capacity; } }
接下来创建一个无购物车实例;
package com.song.spring.scope; 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> getItem(){ return items; } }
在classpath:下的xml文件applicationContext.xml中的Bean配置为:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean id="aaa" class="com.song.spring.scope.Battery"> <property name="name" value="AAA" /> <property name="price" value="2.5" /> </bean> <bean id="cdrw" class="com.song.spring.scope.Disc"> <property name="name" value="CD-RW" /> <property name="price" value="1.5" /> </bean> <bean id="dvdrw" class="com.song.spring.scope.Disc"> <property name="name" value="DVD-RW" /> <property name="price" value="3.0" /> </bean> <bean id="shoppingCart" class="com.song.spring.scope.ShoppingCart" /> </beans>
创建一个运行类:
package com.song.spring.scope; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Product aaa = (Product)context.getBean("aaa"); Product cdrw = (Product)context.getBean("cdrw"); Product dvdrw = (Product)context.getBean("dvdrw"); ShoppingCart cart1 = (ShoppingCart)context.getBean("shoppingCart"); cart1.addItem(aaa); cart1.addItem(cdrw); System.out.println("Shopping Cart1 contains:" + cart1.getItem()); ShoppingCart cart2 = (ShoppingCart)context.getBean("shoppingCart"); cart2.addItem(dvdrw); System.out.println("Shopping Cart2 contains:" + cart2.getItem()); } }
运行结果为:
Shopping Cart1 contains:[AAA 2.5, CD-RW 1.5]
Shopping Cart2 contains:[AAA 2.5, CD-RW 1.5, DVD-RW 3.0]
显然这不是我们想要的结果;我们所要的是每个顾客各获得一个Bean实例,这时就应该将配置文件中的Bean实例的作用域改为prototype;
<bean id="shoppingCart" class="com.song.spring.scope.ShoppingCart" scope="prototype"/>
再运行所得结果为:
Shopping Cart1 contains:[AAA 2.5, CD-RW 1.5]
Shopping Cart2 contains:[DVD-RW 3.0]
这才是我们想要的结果,完毕!