§Play 缓存 API
缓存数据是现代应用程序中常见的优化方式,因此 Play 提供了一个全局缓存。
注意:关于缓存的一个重要点是,它的行为就像缓存应该的那样:您刚刚存储的数据可能会丢失。
对于存储在缓存中的任何数据,都需要制定一个再生策略,以防数据丢失。这种理念是 Play 背后的基本原则之一,它与 Java EE 不同,在 Java EE 中,会话预期在其整个生命周期内保留值。
Play 提供了一个基于 Caffeine 的 CacheApi 实现,以及一个基于 Ehcache 2.x 的传统实现。对于进程内缓存,Caffeine 通常是最佳选择。如果您需要分布式缓存,则有针对 memcached 和 redis 的第三方插件。
§导入缓存 API
Play 为缓存 API 和 Caffeine 和 Ehcache 实现提供了单独的依赖项。
§Caffeine
要获取 Caffeine 实现,请将 caffeine
添加到您的依赖项列表中
libraryDependencies ++= Seq(
caffeine
)
这也会自动设置运行时 DI 的绑定,以便组件可注入。
§EhCache
要获取 EhCache 实现,请将 ehcache
添加到您的依赖项列表中
libraryDependencies ++= Seq(
ehcache
)
这也会自动设置运行时 DI 的绑定,以便组件可注入。
§自定义缓存实现
要仅添加 API,请将 cacheApi
添加到您的依赖项列表中。
libraryDependencies ++= Seq(
cacheApi
)
如果您想为 Cached
助手和 AsyncCacheApi
等定义自己的绑定,而无需依赖任何特定的缓存实现,则 API 依赖项很有用。如果您正在编写自定义缓存模块,则应使用此方法。
§访问缓存 API
缓存 API 由 AsyncCacheApi 和 SyncCacheApi 接口定义,具体取决于您想要异步还是同步实现,并且可以像任何其他依赖项一样注入到您的组件中。例如
import javax.inject.Inject;
import play.cache.*;
import play.mvc.*;
public class Application extends Controller {
private AsyncCacheApi cache;
@Inject
public Application(AsyncCacheApi cache) {
this.cache = cache;
}
// ...
}
注意:API 故意保持最小化,以允许插入各种实现。如果您需要更具体的 API,请使用您的缓存库提供的 API。
使用此简单 API,您可以在缓存中存储数据
CompletionStage<Done> result = cache.set("item.key", frontPageNews);
您可以选择为缓存指定一个过期时间(以秒为单位)
// Cache for 15 minutes
CompletionStage<Done> result = cache.set("item.key", frontPageNews, 60 * 15);
您以后可以检索数据
CompletionStage<Optional<News>> news = cache.get("item.key");
您还可以提供一个 Callable
,它在缓存中找不到值时生成存储值
CompletionStage<News> maybeCached =
cache.getOrElseUpdate("item.key", this::lookUpFrontPageNews);
注意:getOrElseUpdate
在 EhCache 中不是原子操作,而是作为 get
后跟从 Callable
计算值,然后是 set
来实现。这意味着如果多个线程同时调用 getOrElse
,则可能多次计算值。
要从缓存中删除项目,请使用 remove
方法
CompletionStage<Done> result = cache.remove("item.key");
要从缓存中删除所有项目,请使用 removeAll
方法
CompletionStage<Done> resultAll = cache.removeAll();
removeAll()
仅在 AsyncCacheApi
上可用,因为删除缓存中的所有元素很少是您想同步执行的操作。预期是,删除缓存中的所有项目仅在特殊情况下作为管理员操作需要,而不是应用程序正常运行的一部分。
请注意,SyncCacheApi 具有相同的 API,只是它直接返回值,而不是使用 future。
§访问不同的缓存
可以通过名称定义和使用具有不同配置的不同缓存。要访问不同的缓存,在注入它们时,请在您的依赖项上使用 NamedCache 限定符,例如
import javax.inject.Inject;
import play.cache.*;
import play.mvc.*;
public class Application extends Controller {
@Inject
@NamedCache("session-cache")
SyncCacheApi cache;
// ...
}
如果您想访问多个不同的缓存,则需要在application.conf
中告诉 Play 绑定它们,如下所示
play.cache.bindCaches = ["db-cache", "user-cache", "session-cache"]
定义和配置命名缓存取决于您使用的缓存实现,下面给出了使用 Caffeine 配置命名缓存的示例。
§使用 Caffeine 配置命名缓存
如果您想传递一个默认的自定义配置,该配置将用作所有缓存的回退,您可以通过指定以下内容来实现
play.cache.caffeine.defaults = {
initial-capacity = 200
...
}
您还可以通过以下方式为特定缓存传递自定义配置数据
play.cache.caffeine.user-cache = {
initial-capacity = 200
...
}
§使用 EhCache 配置命名缓存
使用 EhCache 实现,默认缓存称为 play,可以通过创建名为 ehcache.xml 的文件来配置。可以使用不同的配置甚至实现来配置其他缓存。
默认情况下,Play 会尝试为您创建名称来自play.cache.bindCaches
的缓存。如果您想在ehcache.xml
中自己定义它们,您可以设置
play.cache.createBoundCaches = false
§设置执行上下文
默认情况下,Caffeine 和 EhCache 将元素存储在内存中。因此,从缓存读取和写入缓存应该非常快,因为几乎没有阻塞 I/O。
但是,根据缓存的配置方式(例如,通过使用EhCache 的DiskStore
),可能会出现阻塞 I/O,这可能会变得过于昂贵,因为即使异步实现也会在默认执行上下文中阻塞线程。
对于这种情况,您可以配置一个不同的Pekko 调度器,并通过play.cache.dispatcher
设置它,以便缓存插件使用它
play.cache.dispatcher = "contexts.blockingCacheDispatcher"
contexts {
blockingCacheDispatcher {
fork-join-executor {
parallelism-factor = 3.0
}
}
}
§Caffeine
使用 Caffeine 时,这将设置 Caffeine 的内部执行器。实际上,设置play.cache.dispatcher
会设置play.cache.caffeine.defaults.executor
。就像上面描述的一样,因此您可以为不同的缓存设置不同的执行器
play.cache.caffeine.user-cache = {
executor = "contexts.anotherBlockingCacheDispatcher"
...
}
§EhCache
对于 EhCache,Play 将在给定调度器的线程上的 Future 中运行任何 EhCache 操作。
§缓存 HTTP 响应
您可以使用标准的Action
组合轻松创建智能缓存操作。
提示:Play HTTP
Result
实例可以安全地缓存并在以后重用。
Play 为标准情况提供了一个默认的内置帮助程序
@Cached(key = "homePage")
public Result index() {
return ok("Hello world");
}
§自定义实现
可以提供缓存 API 的自定义实现。确保您具有cacheApi
依赖项。
然后,您可以实现AsyncCacheApi并在 DI 容器中绑定它。您还可以将SyncCacheApi绑定到DefaultSyncCacheApi,它只是包装了异步实现。
请注意,removeAll
方法可能不受您的缓存实现支持,原因可能是它不可用,或者因为它会造成不必要的低效。如果出现这种情况,您可以在 removeAll
方法中抛出 UnsupportedOperationException
异常。
为了除了默认实现之外,还提供缓存 API 的实现,您可以创建自定义限定符,或者重用 NamedCache
限定符来绑定实现。
§将 Caffeine 与您的自定义实现一起使用
要使用 Caffeine 的默认实现,您需要 caffeine
依赖项,并且您必须在 application.conf
中禁用 Caffeine 模块自动绑定它。
play.modules.disabled += "play.api.cache.caffeine.CaffeineCacheModule"
§将 EhCache 与您的自定义实现一起使用
要使用 EhCache 的默认实现,您需要 ehcache
依赖项,并且您必须在 application.conf
中禁用 EhCache 模块自动绑定它。
play.modules.disabled += "play.api.cache.ehcache.EhCacheModule"
在本文档中发现错误?此页面的源代码可以在 此处 找到。在阅读 文档指南 后,请随时贡献拉取请求。有疑问或建议要分享?前往 我们的社区论坛 与社区进行交流。