文件

§編譯時間依賴性注入

Play 提供了一種執行時期依賴性注入機制,也就是在執行時期才連結依賴性的依賴性注入。這種方法有優缺點,主要優點是減少樣板程式碼,主要缺點是應用程式的建構並未在編譯時期驗證。

另一種方法是使用編譯時間依賴性注入。最簡單來說,編譯時間 DI 可以透過手動建構並連結依賴性來達成。還有其他更進階的技術和工具,例如 Dagger。這些技術和工具都可以輕鬆地實作在建構函式和手動連結上,因此 Play 對編譯時間依賴性注入的支援是提供公開建構函式和工廠方法作為 API。

注意:如果你不熟悉編譯時間 DI 或一般的 DI,建議閱讀 Adam Warski 的 Scala 的 DI 指南,其中討論了編譯時間 DI 的一般概念。雖然這是針對 Scala 開發人員的說明,但也可以讓你了解編譯時間注入的優點。

除了提供公開建構函式和工廠方法外,所有 Play 的現成模組都提供一些實作蛋糕模式輕量級形式的介面,以提供便利性。這些介面建立在公開建構函式的基礎上,而且完全是選用的。在某些應用程式中,它們可能不適合使用,但在許多應用程式中,它們會是很方便的機制,可用於連接 Play 提供的元件。這些介面的命名慣例是使用 Components 結尾,例如,DB API 的預設 HikariCP 實作提供一個稱為 HikariCPComponents 的介面。

注意:當然,Java 有些限制,無法完全實作蛋糕模式。例如,您無法在介面中擁有狀態。

在以下範例中,我們將展示如何使用內建元件輔助介面手動連接 Play 應用程式。透過閱讀提供的元件介面的原始碼,也可以很輕鬆地將此適應到其他依賴注入技術。

§應用程式進入點

在 JVM 上執行的每個應用程式都需要一個由反射載入的進入點,即使您的應用程式自行啟動,主類別仍會由反射載入,而且其主方法會使用反射來尋找和呼叫。

在 Play 的開發模式中,Play 使用的 JVM 和 HTTP 伺服器必須在您的應用程式重新啟動之間持續執行。為了實作這一點,Play 提供一個 ApplicationLoader 介面,您可以實作這個介面。每次重新載入應用程式時,都會建構和呼叫應用程式載入器,以載入應用程式。

此介面的載入方法採用應用程式載入器 Context 作為引數,其中包含 Play 應用程式所需的所有元件,這些元件會比應用程式本身更長久,且無法由應用程式本身建構。其中有許多元件特別用於在開發模式中提供功能,例如,來源對應器允許 Play 錯誤處理常式呈現發生例外狀況的地方的來源程式碼。

最簡單的實作方式是延伸 Play BuiltInComponentsFromContext 抽象類別。此類別採用 context,並根據該 context 提供所有內建元件。您只需要提供一個路由器,讓 Play 能將要求路由到適當的地方。以下是使用空路由器以這種方式建立的最簡單應用程式

import play.Application;
import play.ApplicationLoader;
import play.BuiltInComponentsFromContext;
import play.LoggerConfigurator;
import play.controllers.AssetsComponents;
import play.db.ConnectionPool;
import play.db.HikariCPComponents;
import play.filters.components.HttpFiltersComponents;
import play.mvc.Results;
import play.routing.Router;
import play.routing.RoutingDslComponentsFromContext;
public class MyComponents extends BuiltInComponentsFromContext implements HttpFiltersComponents {

  public MyComponents(ApplicationLoader.Context context) {
    super(context);
  }

  @Override
  public Router router() {
    return Router.empty();
  }
}

然後是應用程式載入器

public class MyApplicationLoader implements ApplicationLoader {

  @Override
  public Application load(Context context) {
    return new MyComponents(context).application();
  }
}

若要設定 Play 使用此應用程式載入器,請設定 play.application.loader 屬性,使其指向 application.conf 檔案中的完全限定類別名稱

play.application.loader=MyApplicationLoader

此外,如果您正在修改使用內建 Guice 模組的現有專案,您應該能夠從 build.sbt 中的 libraryDependencies 中移除 guice

§提供路由器

若要設定路由器,您有兩個選項,使用 RoutingDsl 或產生的路由器。

§使用 RoutingDsl 提供路由器

為了讓這更容易,Play 有 RoutingDslComponentsFromContext 類別,它已經提供一個 RoutingDsl 執行個體,使用其他提供的組件建立

public class MyComponentsWithRouter extends RoutingDslComponentsFromContext
    implements HttpFiltersComponents {

  public MyComponentsWithRouter(ApplicationLoader.Context context) {
    super(context);
  }

  @Override
  public Router router() {
    // routingDsl method is provided by RoutingDslComponentsFromContext
    return routingDsl().GET("/path").routingTo(request -> Results.ok("The content")).build();
  }
}

§使用產生的路由器

預設情況下,Play 會使用 注入路由產生器。這會產生一個路由器,其建構函式會接受路由檔案中的每個控制器和包含的路由器,依據它們在路由檔案中出現的順序。路由器的建構函式也會在第一個參數接受 play.api.http.HttpErrorHandlerplay.http.HttpErrorHandler 的 Scala 版本),用於處理參數繫結錯誤,並在最後一個參數接受一個字串前綴。也會提供一個將此預設為 "/" 的重載建構函式。

下列路由

GET        /                    controllers.HomeController.index
GET        /assets/*file        controllers.Assets.at(path = "/public", file)

會產生一個路由器,它會接受 controllers.HomeControllercontrollers.Assets 和任何其他已宣告路由的執行個體。要在實際應用程式中使用這個路由器

public class MyComponentsWithGeneratedRouter extends BuiltInComponentsFromContext
    implements HttpFiltersComponents, AssetsComponents {

  public MyComponentsWithGeneratedRouter(ApplicationLoader.Context context) {
    super(context);
  }

  @Override
  public Router router() {
    HomeController homeController = new HomeController();
    Assets assets =
        new Assets(scalaHttpErrorHandler(), assetsMetadata(), environment().asScala());
return new router.Routes(scalaHttpErrorHandler(), homeController,
    return new javaguide.dependencyinjection.Routes(
            scalaHttpErrorHandler(), homeController, assets)
        .asJava();
  }
}

§設定記錄

要在 Play 中正確設定記錄,必須在傳回應用程式之前執行 LoggerConfigurator。預設的 BuiltInComponentsFromContext 沒有為你呼叫 LoggerConfigurator

必須在應用程式載入器中新增這個初始化程式碼

import scala.jdk.javaapi.OptionConverters;
public class MyAppLoaderWithLoggerConfiguration implements ApplicationLoader {
  @Override
  public Application load(Context context) {

    LoggerConfigurator.apply(context.environment().classLoader())
        .ifPresent(
            loggerConfigurator ->
                loggerConfigurator.configure(context.environment(), context.initialConfig()));

    return new MyComponents(context).application();
  }
}

§使用其他組件

如前所述,Play 提供許多輔助特質,用於連接其他組件。例如,如果你想要使用資料庫連線池,你可以將 HikariCPComponents 混入你的組件 cake,如下所示

public class MyComponentsWithDatabase extends BuiltInComponentsFromContext
    implements HikariCPComponents, HttpFiltersComponents {

  public MyComponentsWithDatabase(ApplicationLoader.Context context) {
    super(context);
  }

  @Override
  public Router router() {
    return Router.empty();
  }

  public SomeComponent someComponent() {
    // connectionPool method is provided by HikariCPComponents
    return new SomeComponent(connectionPool());
  }
}

其他輔助特質也可用作 CSRFComponentsAhcWSComponents。提供元件的 Java 介面的完整清單如下:

下一頁:應用程式設定


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