跳到主要内容

理解缓存抽象

ChatGPT-4o 中英对照 Understanding the Cache Abstraction

缓冲区与缓存

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

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

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

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

important

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

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

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

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

important

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

如果你有一个多进程环境(即,一个部署在多个节点上的应用程序),你需要相应地配置你的缓存提供者。根据你的使用场景,在多个节点上复制相同的数据可能已经足够。然而,如果你在应用程序运行过程中更改了数据,你可能需要启用其他传播机制。

缓存特定项目直接等同于程序化缓存交互中常见的“如果未找到则获取,然后继续并最终放入”的代码块。没有应用锁,多个线程可能会同时尝试加载相同的项目。逐出操作也是如此。如果多个线程尝试同时更新或逐出数据,您可能会使用过时的数据。某些缓存提供者在这方面提供高级功能。有关更多详细信息,请参阅缓存提供者的文档。

要使用缓存抽象,您需要注意两个方面:

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

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