理解缓存抽象

缓存与缓冲区

术语“缓冲区”和“缓存”往往可以互换使用。但是需要注意的是,它们代表不同的东西。传统上,缓冲区用作快速实体和慢速实体之间数据的中间临时存储。由于一方必须等待另一方(这会影响性能),缓冲区通过允许一次移动整个数据块而不是小块数据来缓解这种情况。数据仅从缓冲区写入和读取一次。此外,缓冲区至少对知道它的一个参与方可见。

另一方面,缓存根据定义是隐藏的,任何一方都不知道发生了缓存。它也提高了性能,但它通过让相同的数据以快速的方式多次读取来做到这一点。

您可以在此处找到缓冲区和缓存之间差异的进一步解释。

缓存抽象的核心是将缓存应用于Java方法,从而根据缓存中可用的信息减少执行次数。也就是说,每次调用目标方法时,抽象都会应用一种缓存行为,检查是否已经为给定的参数调用了该方法。如果已调用,则返回缓存的结果,而无需调用实际的方法。如果未调用该方法,则调用该方法,并将结果缓存并返回给用户,以便下次调用该方法时返回缓存的结果。这样,可以只为给定的一组参数调用一次昂贵的(CPU或IO绑定)方法,并重用结果,而无需再次实际调用该方法。缓存逻辑以透明的方式应用,不会对调用者造成任何干扰。

这种方法仅适用于保证无论调用多少次都能为给定输入(或参数)返回相同输出(结果)的方法。

缓存抽象提供其他与缓存相关的操作,例如更新缓存内容或删除一个或所有条目。如果缓存处理在应用程序过程中可能发生变化的数据,这些操作非常有用。

与Spring框架中的其他服务一样,缓存服务是一个抽象(而不是缓存实现),需要使用实际的存储来存储缓存数据——也就是说,抽象使您无需编写缓存逻辑,但没有提供实际的数据存储。这个抽象由org.springframework.cache.Cacheorg.springframework.cache.CacheManager接口实现。

Spring提供了一些该抽象的实现:基于JDK java.util.concurrent.ConcurrentMap 的缓存、Gemfire缓存、Caffeine和符合JSR-107的缓存(例如Ehcache 3.x)。有关插入其他缓存存储和提供程序的更多信息,请参阅插入不同的后端缓存

缓存抽象对多线程和多进程环境没有特殊处理,因为此类功能由缓存实现处理。

如果您有多进程环境(即部署在多个节点上的应用程序),则需要相应地配置缓存提供程序。根据您的用例,在多个节点上复制相同的数据就足够了。但是,如果您在应用程序过程中更改数据,则可能需要启用其他传播机制。

缓存特定项目直接等同于使用编程缓存交互找到的典型get-if-not-found-then-proceed-and-put-eventually代码块。不应用锁,并且多个线程可能会同时尝试加载相同的项目。驱逐也适用。如果多个线程同时尝试更新或驱逐数据,则您可能会使用过时的数据。某些缓存提供程序在该领域提供高级功能。有关更多详细信息,请参阅您的缓存提供程序的文档。

要使用缓存抽象,您需要处理两个方面

  • 缓存声明:标识需要缓存的方法及其策略。

  • 缓存配置:存储和读取数据的后备缓存。