简体   繁体   English

在单例 bean 中将共享数据结构(例如缓存)实现为 concurrentHashMap

[英]Implementing shared data structure (e.g. cache) as a concurrentHashMap in a singleton bean

I am implementing an HTTP API using the Spring MVC framework.我正在使用 Spring MVC 框架实现 HTTP API。

I want to store some data between requests and between sessions.我想在请求之间和会话之间存储一些数据。 The data needs to be readable and modifiable by multiple requests in completely independent sessions, but it only needs to exist in-memory while the application is running, it does not need to be persisted to a database, and it does not need to be shared between any scaled-up, multi-node, multi-process server backend design, just one per (eg) Tomcat instance is completely fine.数据需要在完全独立的会话中被多个请求读取和修改,但只需要在应用程序运行时存在于内存中,不需要持久化到数据库,也不需要共享在任何放大的、多节点、多进程的服务器后端设计之间,每个(例如)Tomcat 实例只有一个就可以了。 Consider for example a cache or something logging some short-lived metrics about the application-specific data coming in through the requests.例如,考虑一个缓存或记录一些关于通过请求传入的应用程序特定数据的短期指标。

I am assuming the usual way would be to use an in-memory database or something like Redis.我假设通常的方法是使用内存数据库或类似 Redis 的东西。 However, this being my first venture into web stuff and coming from c++ parallel computing personally, this seems like an extremely over-engineered and inefficient solution to me.然而,这是我第一次涉足网络领域,并且个人来自 c++ 并行计算,这对我来说似乎是一个极度过度设计和低效的解决方案。

Can I not just create a singleton bean containing a ConcurrentHashMap of my required types, inject it as a dependency into my Controller, and be done with it?我是否可以不只是创建一个包含所需类型的 ConcurrentHashMap 的单例 bean,将其作为依赖项注入到我的 Controller 中,然后完成它? I never see anyone talk about this anywhere, even though it seems to be the simplest solution by far to me.我从来没有看到有人在任何地方谈论过这个,尽管它似乎是迄今为止对我来说最简单的解决方案。 Is there something about how Spring MVC or Tomcat works that makes this impossible?关于 Spring MVC 或 Tomcat 的工作方式是否有什么使这成为不可能的?

Basically, yes.基本上,是的。 "A singleton ConcurrentHashMap" can be used as a cache. “单例 ConcurrentHashMap”可以用作缓存。

But, I'd go with something that works like a map but has an API that is specifically tailored to caches.但是,我会使用类似于地图但具有专门为缓存量身定制的 API 的东西。 Fortunately, such a thing exists.幸运的是,这样的事情是存在的。

Guava is a 'general utilities' project (just a bunch of useful utility classes, lots of em now seem a bit pointless, in the sense that java.util and co have these too, but guava is over 10 years old, and everything it has didn't exist back then) - and one of the most useful things it has is a 'Cache' class. Guava 是一个“通用实用程序”项目(只是一堆有用的实用程序类,很多 em 现在看起来有点毫无意义,因为java.util和 co 也有这些,但是 guava 已经超过 10 年了,它的一切那时还不存在)-它拥有的最有用的东西之一是“缓存”类。 It's a Map with bonus features.这是一张带有奖励功能的地图。

I strongly suggest you use it and follow its API designs.强烈建议你使用它并遵循它的 API 设计。 It's got a few things that map doesn't have:它有一些地图没有的东西:

  • You can set up an eviction system;您可以设置驱逐系统; various strategies are available.有多种策略可供选择。 You can allow k/v pairs to expire X milliseconds after being created, or optionally X milliseconds after the last time they were read.您可以允许 k/v 对在创建后 X 毫秒后过期,或者在最后一次读取它们后 X 毫秒内过期。 Or simply guarantee that the cache will never exceed some set size, removing the least recently accessed (or written - again, your choice) k/v pair if needed.或者简单地保证缓存永远不会超过某个设定的大小,如果需要,删除最近最少访问(或写入 - 再次,您的选择)的 k/v 对。
  • The obvious 'get a value' API call isn't .get() like with map, it's a variant where you provide the key as well as a computation function that would calculate the value;显而易见的“获取值”API 调用与 map 不同的是.get() ,它是一种变体,您可以在其中提供密钥以及计算值的计算函数; the Cache object will just return the cache value if it exists, but if not, it will run the computation, store it in the cache, and return that. Cache 对象将只返回缓存值(如果存在),但如果不存在,它将运行计算,将其存储在缓存中,然后返回。 Making your life a lot easier, you just call the get method, pass in the key and the computer, and continue, not having to care about whether the computation function is used or not.让你的生活更轻松,你只需调用 get 方法,传入密钥和计算机,然后继续,不必关心是否使用计算函数。
  • You get some control over concurrent calculations too - if 2 threads simultaneously end up wanting the value for key K which isn't in the cache, should both threads just go compute it, or should one thread be paused to wait for the other's calculation?您也可以对并发计算进行一些控制 - 如果 2 个线程同时最终想要不在缓存中的键 K 的值,两个线程应该只计算它,还是应该暂停一个线程以等待另一个线程的计算? That's also not entirely trivial to write in a ConcurrentHashMap.这在 ConcurrentHashMap 中编写也不是一件容易的事。
  • Some fairly fancy footwork - weak keying/valuing: You can set things up such that if the key is garbage collected, the k/v pair gets evicted (eventually) too.一些相当花哨的步法 - 弱键控/估值:您可以进行设置,如果密钥被垃圾收集,则 k/v 对也会(最终)被驱逐。 This is tricky (string keys don't really work here, for example, and sometimes your value refers to your key in which case the existence of the value would mean your key can't be GCed, making this principle worthless - so you need to design your key and value classes carefully), but can be very powerful.这很棘手(例如,字符串键在这里实际上不起作用,有时您的值指的是您的键,在这种情况下,值的存在意味着您的键不能被 GC,使得这个原则毫无价值 - 所以你需要仔细设计您的键和值类),但可能非常强大。

I believe you can also get just the guava cache stuff on its own, but if not - you know where to look: Add guava as a dependency to your project, fire up an instance of CacheBuilder , read the javadocs , and you're off :)我相信你也可以自己获得 guava 缓存的东西,但如果没有 - 你知道在哪里看:将 guava 作为依赖项添加到项目中,启动CacheBuilder的实例, 阅读 javadocs ,然后你就走了:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 可配置(例如XML)的Java Bean到Bean映射框架 - Configurable (e.g. XML) Java Bean to Bean Mapping Framework 使用函数/构造函数 arguments 创建 Singleton(例如注入有用) - Create Singleton with function/constructor arguments (usefull for e.g. injection) Singleton Bean用于快速访问共享数据 - Singleton Bean for quick access to shared data 使用java ConcurrentHashMap实现缓存 - Implementing a cache using a java ConcurrentHashMap Concurrenthashmap迭代器数据结构 - Concurrenthashmap Iterator data structure 我们可以修改或自定义Java对象的数据结构(例如树,链表等)吗? - Can we modify or customise the data structure(for e.g. tree, Linked List etc.) of Java object(s)? 有没有办法使用 skyve 验证器(例如电子邮件)来测试不是 bean 属性的值? - Is there a way to use a skyve validator (e.g. email) to test a value which isn't an attribute on a bean? 将GAE XMPP服务实现为现有XMPP服务器(例如ejabberd或OpenFire)的外部组件 - implementing GAE XMPP service as an external component to an existing XMPP server (e.g. ejabberd or OpenFire) 可以使用反射来获得具体的实现类型(例如Class <? extends MyInterface> )? - Can reflection be used to get a concrete implementing type (e.g. Class<? extends MyInterface>)? 强制 JVM 在没有页面缓存的情况下执行所有 IO(例如 O_DIRECT) - Force JVM to do all IO without page cache (e.g. O_DIRECT)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM