文件

§Play 快取 API

快取資料是現代應用程式中常見的最佳化方式,因此 Play 提供了全球快取。

注意:快取的一個重要重點是,它的行為就像快取一樣:您剛剛儲存的資料可能會消失。

對於快取中儲存的任何資料,都需要制定一個再生策略,以防資料消失。此哲學是 Play 背後的基本原則之一,與 Java EE 不同,Java EE 預期會話會在其生命週期中保留值。

Play 提供一個基於 Caffeine 的 CacheApi 實作,以及一個基於 Ehcache 2.x 的舊版實作。對於處理中的快取,Caffeine 通常是最佳選擇。如果您需要分散式快取,有 memcachedredis 的第三方外掛程式。

§匯入快取 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 由 AsyncCacheApiSyncCacheApi 介面定義,視您是要非同步或同步實作而定,而且可以像其他任何相依性一樣注入到您的元件中。例如

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,只不過它直接傳回值,而不是使用未來值。

§存取不同的快取

可以根據名稱定義和使用具有不同組態的不同快取。要存取不同的快取,請在注入快取時,在相依項上使用 NamedCache 限定詞,例如

import javax.inject.Inject;
import play.cache.*;
import play.mvc.*;

public class Application extends Controller {

  @Inject
  @NamedCache("session-cache")
  SyncCacheApi cache;

  // ...
}

如果您想要存取多個不同的快取,則需要告知 Play 在 application.conf 中繫結它們,如下所示

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"

下一步:使用 Play WS 呼叫 REST API


在這個文件中發現錯誤?此頁面的原始碼可以在 這裡 找到。在閱讀 文件指南 之後,請隨時提交拉取請求。有問題或建議要分享嗎?請前往 我們的社群論壇 與社群展開對話。