1、Spring中bean 的多种作用域
- 单例(Singleton):整个应用中只创建一个bean 的实例,Spring默认创建单例的bean;
- 原型(Prototype):每次注入or通过Spring应用上下文获取时,创建一个新的bean实例;
- 会话(Session):在web应用中,为每个会话创建一个bean实例,例如用户购物车的bean;
- 请求(Request):在web应用中,为每个请求创建一个bean实例;
2、设置会话(Session)作用域
@Component
@Scope{ value=WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES }
public ShoppingCart cart(){...}
3、购物车场景中的作用域代理——延迟注入请求和会话作用域的bean。
假设将ShoppingCart bean注入到单例StoreService bean的Setter方法中:
@Component
public class StoreService{
public void setShoppingCart(ShoppingCart shoppingCart){
this.shoppingCart=shoppingCart;
}
...
}
系统中每个用户拥有一个ShoppingCart实例,我们并不想让Spring注入某个固定的ShoppingCart实例到StoreService中,我们希望的是当StoreService处理购物车功能时,它使用的ShoppingCart恰好是当前会话对应的哪一个。
Spring会注入一个到ShoppingCart bean的代理,而不是一个实际的ShoppingCart bean。这个代理会暴露与ShoppingCart相同的方法,所以StoreService会认为它就是一个购物车。
而当实际调用ShoppingCart中的方法时,代理会进行懒解析并将调用委托给会话作用域内的真正的ShoppingCart bean!!
同样,请求作用域的bean也会面临相同的装配问题,也可以通过注入作用域代理解决。
4、作用域代理——延迟注入请求和会话作用域的bean
上面我们使用接口来作为作用域代理,其实也可以使用具体类。
此时,Spring必须使用CGLib来生成基于类的代理:
proxyMode=ScopedProxyMode.TARGET_CLASS
5、XML中声明作用域代理
<bean id="cart" class="xx.xxx.ShoppingCart" scope="session">
<aop:scoped-proxy />
</bean>
<aop:scoped-proxy>即告诉Spring使为bean创建一个作用域代理,切默认使用CGLib创建目标类的代理。
我们也可以通过设置来生成基于接口的代理:
<bean id="cart" class="xx.xxx.ShoppingCart" scope="session">
<aop:scoped-proxy proxy-target-class="false" />
</bean>