Spring bean 有四种默认的作用域:
- 单例(singleton)
- 原型(prototype)
- 会话(session)
- 请求(request)
单例
单例模式很多人都手撸过,在默认情况下,Spring bean 都是单例的,即在整个应用中,无论某个bean被注入多少次,注入的都是同一个实例。这为初始化和垃圾回收降低了成本。
原型
在一些情况下,bean无法保持无状态,他们会保持自己的一些状态,此时,重用是不安全的。原型模式是每次从上下文检索该bean的时候,都会创建新的实例。
请求和会话
在web应用中,使用request和session为作用域是很常见的场景。假设有一个购物车,使用单例是不合适的,因为这将会使得所以用户都往一个购物车中添加商品。使用原型也是不合适的,因为这会让用户在模块之间无法重用这个bean。
所以请求和会话是有意义的,但是也需要注意一些情况。
设想:购物车(ShoppingCart)是基于session的,但是整个电商系统中的购物服务(ShoppingService)是singleton的。ShoppingService是上下文初始化时加载的,而ShoppingCart是在用户进入应用,创建了会话时才会创建。现在我们需要将ShoppingCart注入到ShoppingService,多个用户就会产生多个不同的ShoppingCart,这似乎会产生新的问题。
理想的状态是:ShoppingService希望被注入当前正在使用的ShoppingCart。所以,注入ShoppingService的并不是ShoppingCart本身,而是它的代理。此时可以使用@ScopedProxyMode.INTERFACES
或@ScopedProxy.TARGET_CLASS
。
区别在于你注入的是一个实际的类还是一个抽象的接口。
以上是关于Spring bean 作用域的一点笔记,如有谬误或改良,还请指正。