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中所出现的问题。以下是该属性解决的问题场景。
假如要把
ShoppingCartbean注入到StoreService单例bean的set方法中,如下:
@Component
public class StoreService {
private ShoppingCart shoppingCart;
public void setShoppingCart(ShoppingCart shoppingCart) {
this.shoppingCart = shoppingCart;
}
}
因为
StoreService是一个单例的bean,会在Spring应用上下文加载的时候创建。当它创建的时候,Spring会试图将ShoppingCartbean注入到set方法中。但是ShoppingCartbean是会话作用域,此时并不存在。知道某个用户进入系统,创建会话之后,才会出现ShoppingCart实例。
另外,多个会话产生多个
ShoppingCart实例,我们希望StoreService使用的ShoppingCart实例是当前会话的。
Spring并不会将实际的ShoppingCartbean注入到StoreService中,Spring会注入一个到ShoppingCartbean的代理,如下图。这个代理会暴露与ShoppingCart相同的方法,当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正ShoppingCartbean。
