Spring
作用域定义
默认情况下,Spring
应用上下文中的bean都是以单例(singleton)的形式创建的。
Spring
定义了多种作用域,可以基于这些作用域创建bean:
- 单例(Singleton):在整个应用中,只创建bean一个实例。
- 原型(Prototype):在每次注入或
Spring
应用上下文获取的时候,都会创建一个新的bean实例。 - 会话(Session):在Web应用中,为每个会话创建一个bean实例。
- 请求(Request):在Web应用中,为每个请求创建一个bean实例。
1.组件扫描的方式
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class NotePad {
}
2.Java配置的方式
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public NotePad notePad(){
return new NotePad();
}
3.XML配置的方式
<bean id="notePad" class="com.ql.NotePad" scope="prototype"/>
使用会话和请求作用域
在Web应用中,如果能够实例化会话和请求范围内共享的bean,将是非常有价值的事情。如在电子商务应用中,可能用一个bean代表购物车。如果该bean是单例,就会导致导致所有用户都会向同一个购物车添加商品。如果购物车是原型作用域,那么在应用中某个地方向购物车添加商品,在应用的另一个地方可能就用不了。
就购物车的bean来说,会话作用域是最合适的:
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION,
proxyMode = ScopedProxyMode.INTERFACES
)
public class ShoppingCart {
}
@Scope
的value
设置成session
。另一个属性proxyMode
设置为ScopedProxyMode.INTERFACES
,这个属性解决了将会话或请求作用域的bean注入到单例bean中所出现的问题。以下是该属性解决的问题场景。
假如要把
ShoppingCart
bean注入到StoreService
单例bean的set方法中,如下:
@Component
public class StoreService {
private ShoppingCart shoppingCart;
public void setShoppingCart(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
}
因为
StoreService
是一个单例的bean,会在Spring
应用上下文加载的时候创建。当它创建的时候,Spring
会试图将ShoppingCart
bean注入到set方法中。但是ShoppingCart
bean是会话作用域,此时并不存在。知道某个用户进入系统,创建会话之后,才会出现ShoppingCart
实例。
另外,多个会话产生多个
ShoppingCart
实例,我们希望StoreService
使用的ShoppingCart
实例是当前会话的。
Spring
并不会将实际的ShoppingCart
bean注入到StoreService
中,Spring
会注入一个到ShoppingCart
bean的代理,如下图。这个代理会暴露与ShoppingCart
相同的方法,当StoreService
调用ShoppingCart
的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正ShoppingCart
bean。