Play 2.6 在Play中使用缓存
使用缓存
https://playframework.com/documentation/2.6.x/JavaCache
对数据进行缓存是一种很常见的优化方式,Play也提供了全聚德缓存。对于cache有一点很重要,缓存只能做缓存能做的:你刚保存的数据也许会丢失。
对于任何保存在缓存中的数据,当数据丢失时需要一个重新生成的策略。这个哲学存在于Play的基础之中,而且与Java EE不同,session被期待在整个生命周期中保存数据。
Play默认的缓存API是Ehcache
导入缓存API
Play提供了API和默认的Ehcache实现。可以通过以下配置获取完全的Ehcache实现
libraryDependencies ++= Seq(
ehcache
)
这会在运行时自动进行注入。
如果只想添加API,可以使用如下配置
libraryDependencies ++= Seq(
cacheApi
)
如果你先定义自己的Cached
helper和AsynCacheAPI
不依赖域Ehcache的绑定,这个API依赖会很有用。如果你使用自己定的缓存模块只能使用这个配置。
JCache的支持
Ehcache支持JSR107标准,也被成为JCache,但是Play默认不绑定javax.caching.CacheManager。为了绑定javax.caching.CacheManager给默认的provider,添加以下配置
libraryDependencies += jcache
如果你使用Guice,可以通过下面的配置来添加Java注解
libraryDependencies += "org.jsr107.ri" % "cache-annotations-ri-guice" % "1.0.0"
获取缓存API
缓存API定义在AsyncCacheAPI和SyncCacheAPI两个接口中,根据你需要同步或者异步的实现,注入到你的类中
import play.cache.*;
import play.mvc.*;
import javax.inject.Inject;
public class Application extends Controller {
private AsyncCacheApi cache;
@Inject
public Application(AsyncCacheApi cache) {
this.cache = cache;
}
// ...
}
Note: The API is intentionally minimal to allow various implementations to be plugged in. If you need a more specific API, use the one provided by your Cache library. |
向缓存中写数据
CompletionStage<Done> result = cache.set("item.key", frontPageNews);
也可以设置一个时间(以秒为单位)
// Cache for 15 minutes
CompletionStage<Done> result = cache.set("item.key", frontPageNews, 60 * 15);
读取数据
CompletionStage<News> news = cache.get("item.key");
也可以提供一个Callabel
在缓存中数据不存在时生成一个
CompletionStage<News> maybeCached = cache.getOrElseUpdate("item.key", this::lookUpFrontPageNews);
注意:getOrElseUpdate
在Ehcache中不是一个原子操作,在实现上先是一个get操作然后是从Callable中计算值最后是set操作。这意味着在多线程的情况下会被计算多次。
删除一个信息
CompletionStage<Done> result = cache.remove("item.key");
清空cache
CompletionStage<Done> resultAll = cache.removeAll();
removeAll()
只在异步API中可用,因为很少有情况你需要同步清空cache。只有在一些特殊情况下才需要管理员来清空cache,这不是应用的常规操作。
SyncCacheApi具有相同的API,只是返回值不是用future封装的。
获取不同的缓存
在默认的Ehcache实现中,默认的缓存叫做play,可以通过ehcache.xml进行配置。别的缓存可以使用不同的配置甚至是不同的实现。
如果你需要多种不同的缓存,可以在application.conf中进行绑定
play.cache.bindCaches = ["db-cache", "user-cache", "session-cache"]
默认情况下Play会为你创建这些缓存。如果你想要在ehcache.xml中进行配置,你可以选择
play.cache.createBoundCaches = false
为了在注入时获取不同的缓存,在依赖上使用NamedCache。
import play.cache.*;
import play.mvc.*;
import javax.inject.Inject;
public class Application extends Controller {
@Inject @NamedCache("session-cache") SyncCacheApi cache;
// ...
}
设定执行上下文
默认情况下Ehcache操作都是阻塞的,异步的实现会阻塞默认执行上下文的线程。
如果你使用Play的默认设置一般情况下不会有问题,只会在内容中存数据所以需要读的尽可能快。
考虑到Ehcache的配置和数据存贮的介质。使用阻塞操作可能太浪费了。
你可以配置一个不同的Akka dispatcher,然后通过play.cache.dispatcher来配置
play.cache.dispatcher = "contexts.blockingCacheDispatcher"
contexts {
blockingCacheDispatcher {
fork-join-executor {
parallelism-factor = 3.0
}
}
}
缓存HTTP响应
通过Action组合可以很容易实现
@Cached(key = "homePage")
public Result index() {
return ok("Hello world");
}
自定义的缓存实现
你可以提供一个自定义的实现来取代或者和默认实现一起使用。
如果要取代默认实现,只需要在build.sbt中添加依赖。如果仍需要Ehcache的实现,可以在application.conf中停用自动绑定
play.modules.disabled += "play.api.cache.ehcache.EhCacheModule"
你可以实现AsyncCacheApi然后绑定到DI容器中。也可以将SyncCacheApi绑定到 DefaultSyncCacheApi中。
注意你的实现不支持removeAll方法,也许是不可能实现也许是不必要。你可以在removeAll方法中抛出一个UnsupportedOperationException 。
为了提供一个缓存API实现,你可以自己创建一个qualifier或者重用NamedCache来绑定你的实现。
上一篇: Vue2.6-父子组件之间值传递
推荐阅读
-
在ASP.NET 2.0中操作数据之五十六:使用ObjectDataSource缓存数据
-
在ASP.NET 2.0中操作数据之五十九:使用SQL缓存依赖项SqlCacheDependency
-
Objective-C的缓存框架EGOCache在iOS App开发中的使用
-
在ASP.NET 2.0中操作数据之五十六:使用ObjectDataSource缓存数据
-
Objective-C的缓存框架EGOCache在iOS App开发中的使用
-
【转载】在AspNetCore 中 使用Redis实现分布式缓存
-
在AspNetCore 中 使用Redis实现分布式缓存
-
Play 2.6 使用JPA
-
Play 2.6 在Play中使用缓存
-
Play 2.6 使用Play WS调用REST API