应用场景

当我们对设置bean的作用域@Scope时,有个购物车场景,通常我们将商城的bean设为Singleton单例,购物车对于每个用户毫无疑问是单独所有的,设购物车的bean为Session

@Component
@Scope(
        value = WebApplicationContext.SCOPE_SEESION,
        proxyMode = ScopedProxyMode.TARGET_CLASS
)
public class ShoppingCart {
}
@Component
public class StoreService {
    private ShoppingCart shoppingCart;

    @Autowired
    public void setShoppingCart(ShoppingCart shoppingCart){
        this.shoppingCart = shoppingCart;
    }
}

问题

因为StoreService是一个单例的bean,会在Spring应用上下文加载的时候创建。当它创建的时候,Spring会试图将ShoppingCart的bean注入到setShoppingCart()方法中。

但是ShoppingCart的bean是会话作用域的,此时并不存在。直到某个用户进入系统,创建了会话之后,才会出现ShoppingCart实例。

另外,系统中将会有多个ShoppingCart实例:每个用户一个。我们并不想让Spring注入某个固定的ShoppingCart实例到StoreService中。因为每个用户应该持有自己哪个购物车。

解决

通过给@Scope设置proxyMode参数。Spring将不会将实际的ShoppingCart的bean注入到StoreService中。

Spring会注入到一个ShoppingCart的bean的代理。这个代理会暴露与ShoppingCart相同的方法,所以StoreService会认为它就是一个购物车。但是,当StoreService调用ShoppingCart的方法时,代理会对其进行懒解析并将调用委托给会话作用域内真正的ShoppingCart的bean。

注意

ScopedProxyMode.INTERFACES是用于接口的。

具体的类,需要使用ScopedProxyMode.TARGET_CLASS

01-15 11:25