在SpringSingletonBean中存储状态(添加了线程安全机制)是一个好的实践吗

ttp71kqs  于 2023-03-22  发布在  Spring
关注(0)|答案(3)|浏览(123)

Spring doc:
7.5.2(...)通常,对所有有状态bean使用原型作用域,对无状态bean使用单例作用域。
案例:
我有一个独立的应用程序需要存储状态(例如,一些非常简单的缓存实现为简单的Map)。在我看来,最简单的解决方案是创建具有单例范围的Sping Bean,并将HashMap/ConcurrentHashMap放在那里,并添加线程安全的get/set方法。
是好的解决方案/做法或不是?如果不是-什么是正确的方法来做它?

pw9qyyiw

pw9qyyiw1#

使用自定义构建的Spring组件可能会导致混乱(竞争条件,缓存丢失...)。
那怎么办呢?
为什么不简单地使用Spring的CacheManager?它可以作为bean手动注入。该高速缓存可以是“set”或“get”。并且您可以使用缓存驱逐策略使其完全注解驱动:

// Cache collection after the first invocation
@Cacheable("people")
public List<Person> getPeople() {...}

// Refresh entries after altering or inserting a new instance of Person
@CacheEvict(value="people", allEntries = true)
public Person save(Person person) {...}

默认的CacheManager实现在后台使用ConcurentHashMap

fwzugrvs

fwzugrvs2#

如果您只需要缓存几个键,并且打算使用ConcurrentHashMap来解决并发性问题(但如果不关心此缓存的性能,您甚至可以使用同步块),那就没事了还有更多开箱即用的解决方案,如Spring @Cached annotation(参见Spring Caching)或其他内存缓存(如Caffeine),它们不仅可以处理并发性和其他比如价值观驱逐。
但更一般地说,缓存很像一个存储库,所以是的,单例范围是这样一个组件的正确范围。

iyzzxitl

iyzzxitl3#

从这个answer看来,术语“有状态”是针对单一依赖的范围。
这意味着,当我们想要一个状态不会在注入该bean的其他两个bean之间共享时,这就是为什么要使用prototype scope - new instance用于每次注入。
因此,对于保存应用程序级缓存,默认范围singleton似乎是一个。
我喜欢这种方法,因为它是直接的和可控的,只要记住线程安全性问题。
(tip:AtomicReference是一个'并发 Package 器',以防您不需要Map)

相关问题