将状态存储在Spring Singleton Bean中是一种好习惯(添加了线程安全机制)

时间:2018-10-23 09:09:35

标签: java spring

摘自Spring doc:

  

7.5.2(...)通常,对所有有状态bean使用原型范围,对无状态bean使用单例范围。

案例:
我有一个需要存储状态的独立应用程序(例如,一些非常简单的缓存实现为简单Map)。在我看来,最简单的解决方案是创建具有单例作用域的Sping Bean,并将其放在HashMap / ConcurrentHashMap中,并添加线程安全的get / set方法。

是好的解决方案/实践吗?如果不是,什么是正确的方法?

3 个答案:

答案 0 :(得分:3)

是,不是。 使用自定义构建的Spring组件可能会导致混乱(竞赛条件,缓存丢失...)。

那该怎么办?

为什么不简单地使用Spring的CacheManager? 它可以作为bean手动注入。缓存可以“设置”或“获取”。 您可以使用缓存逐出策略使它完全由注释驱动:

// 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

答案 1 :(得分:1)

如果您只需要缓存一些键,而您的意思是使用ConcurrentHashMap来解决并发问题(但如果不考虑此缓存的性能,甚至可以使用同步块),那么就可以了。还有更多开箱即用的解决方案,例如Spring @Cached注释,请参见Spring Caching或其他Caffeine的内存缓存中的解决方案,它们不仅要处理并发和其他重要的事情,例如值驱逐。 / p>

但是,一般来说,缓存非常类似于存储库,因此,单例作用域是此类组件的正确选择。

答案 2 :(得分:0)

从此answer 看来“有状态”一词是在单一依赖性的范围内。

意思是,当我们想要一个不会在其他两个注入该bean的bean之间共享的状态时,这就是为什么要使用prototype范围-每个注入的新实例。

因此,为了保存应用程序级缓存,默认作用域singleton似乎是一个。

我喜欢这种方法,因为它简单明了且可控制,请记住线程安全性问题。

(提示:AtomicReference是“并发包装器”,以防您不需要地图)