上一篇博客,介绍了利用@Qualifier消除同种类型Bean之间的歧义性,本篇博客给出JavaBean装配另一高级特性-bean的作用域。
在默认情况下,Spring中应用上下文中所有Bean都是作为单例的形式创建的。换计划说,不管给定的一个bean被注入到其他Bean中多少次,每次注入的都是同一个实例。例如:
定义一个Dog
package com.wygu.spring.animal;
public class Dog implements Animal{
private int index;
private String dogName;
public Dog(String dogName,int index) {
this.dogName = dogName;
this.index = index;
}
@Override
public void walk() {
System.out.println("The Dog name: "+dogName+" is walking"+";index:"+index++);
}
}
在AnimalFactory中同一个bean(id为“dog”)被注入两次
package com.wygu.spring.animal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class AnimalFactory {
private Animal animal1;
private Animal animal2;
public Animal getAnimal1() {
return animal1;
}
@Autowired
@Qualifier("dog")
public void setAnimal1(Animal animal1) {
this.animal1 = animal1;
}
public Animal getAnimal2() {
return animal2;
}
@Autowired
@Qualifier("dog")
public void setAnimal2(Animal animal2) {
this.animal2 = animal2;
}
}
对应xml配置文件为:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<context:annotation-config/>
<bean id="factory1" class="com.wygu.spring.animal.AnimalFactory"/>
<!-- 通过构造器参数索引进行注入 -->
<bean id="dog" class="com.wygu.spring.animal.Dog">
<constructor-arg index="0" value="欧巴"/>
<constructor-arg index="1" value="1"/>
</bean>
</beans>
执行结果为:
The Dog name: 欧巴 is walking;index:1
The Dog name: 欧巴 is walking;index:2
显然bean虽然被注入了两次,但是都是相同的实例。有时候,使用的类是易变的,他们会保持一些状态,因此如果还保持单例是不合适的。
在Spring中定义了多种作用域,我们构造Bean时可以基于这些作用域,主要包括:
- 单例(Singleton):整个应用中,只创建bean的一个实例;
- 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例;
- 会话(Session):在Web应用中,为每个会话创建一个bean实例;
- 请求(Request):在Web应用中,为每个请求创建一个bean实例。
原型作用域(Prototype)
对于上述示例,我们只需要在XML配置中加入:
<bean id="dog" class="com.wygu.spring.animal.Dog" scope="prototype">
<constructor-arg index="0" value="欧巴"/>
<constructor-arg index="1" value="1"/>
</bean>
运行程序,输出为:
The Dog name: 欧巴 is walking;index:1
The Dog name: 欧巴 is walking;index:1
会话作用域(Session)&请求作用域(Request)
在电子商务应用中,需要一个bean对应一个购物车。因为如果购物车是单例模式的话,会导致所有用户共享同一个购物车,如果购物车是原型模式的话,会导致在一个页面中可以添加到该购物车,另一个页面无法正常添加的问题。我们引入会话作用域,可以很完美的解决这个问题。
@Component
@Scope(value=WebApplicationContext.SCOPE_SESSION)
public class CatShoppingCart implements ShoppingCart{
public ShoppingCart getCatShoppingCart(){
return new CatShoppingCart ();
}
}
我们将scope的value设置为WebApplicationContext中的SCOPE_SESSION常量,表明为Web应用中的每个会话创建一个ShoppingCart。对于每个给定的会话,只会创建一个实例。
如果我们在scope作用域中加入代理模式:
@Scope(value=WebApplicationContext.SCOPE_SESSION,proxyMode=ScopedProxyMode.INTERFACES)
proxyMode=ScopedProxyMode.INTERFACES主要可以解决将会话或请求作用域的bean注入到单例bean中所遇到的问题。