理解缓存抽象

Cache 对比 Buffer

术语“buffer”(缓冲区)和“cache”(缓存)倾向于互换使用。然而,请注意它们代表着不同的事物。传统上,buffer 用作快慢实体之间数据的中间临时存储。由于一方必须等待另一方(这会影响性能),buffer 通过允许整块数据一次性移动而不是小块数据来缓解此问题。数据只从 buffer 中写入和读取一次。此外,buffer 对至少一个知晓它的实体是可见的。

另一方面,根据定义,cache 是隐藏的,并且双方都不知道正在进行缓存。它也通过允许相同的数据以快速方式被多次读取来提高性能。

您可以在这里找到关于 buffer 和 cache 之间差异的进一步解释。

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

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

缓存抽象提供了其他与缓存相关的操作,例如更新缓存内容或移除一个或所有条目的能力。如果缓存处理的数据在应用程序运行期间可能发生变化,这些操作就很有用。

与 Spring Framework 中的其他服务一样,缓存服务是一种抽象(而不是缓存实现),需要使用实际存储来存储缓存数据——也就是说,这种抽象使您无需编写缓存逻辑,但不提供实际的数据存储。此抽象通过 org.springframework.cache.Cacheorg.springframework.cache.CacheManager 接口得以具体化。

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

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

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

缓存特定项直接等同于在编程式缓存交互中常见的“获取-如果未找到-则继续并最终放入”代码块。不应用锁,并且多个线程可能尝试同时加载同一项。逐出也是如此。如果多个线程同时尝试更新或逐出数据,您可能会使用陈旧数据。某些缓存提供程序在此领域提供高级功能。有关更多详细信息,请参阅您的缓存提供程序的文档。

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

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

  • 缓存配置:存储数据和从中读取数据的后端缓存。