摘自Spring doc:
7.5.2(...)通常,对所有有状态bean使用原型范围,对无状态bean使用单例范围。
案例:
我有一个需要存储状态的独立应用程序(例如,一些非常简单的缓存实现为简单Map)。在我看来,最简单的解决方案是创建具有单例作用域的Sping Bean,并将其放在HashMap / ConcurrentHashMap中,并添加线程安全的get / set方法。
是好的解决方案/实践吗?如果不是,什么是正确的方法?
答案 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
是“并发包装器”,以防您不需要地图)