gpt4 book ai didi

java - Play Framework 2.5.1 路由和依赖注入(inject)(适用于 Java)

转载 作者:搜寻专家 更新时间:2023-10-31 19:37:23 24 4
gpt4 key购买 nike

我的“路线”文件中有这个:

POST        /accounts/        controllers.AccountsController.createOneAccount

在我的 AccoutsController.java 中:

package controllers;

import com.google.inject.Inject;
import play.Application;
import play.mvc.Controller;
import play.mvc.Result;
import services.AccountService;
import java.io.IOException;

public class AccountsController extends Controller {
@Inject
private Application application;
final String host = application.configuration().getString("db.default.host");
final int port = application.configuration().getInt("db.default.port");
final String dbName = application.configuration().getString("db.default.dbname");

@Inject
private AccountService accountService;
public Result createOneAccount() throws IOException {
return accountService.createOneAccount(request().body().asJson());
}
}

此代码编译正常,但在运行时出现如下错误:

ProvisionException: Unable to provision, see the following errors: 1) Error injecting constructor, java.lang.NullPointerException at controllers.AccountsController.(AccountsController.java:11)
while locating controllers.AccountsController for parameter 1 at router.Routes.(Routes.scala:28) while locating router.Routes while locating play.api.inject.RoutesProvider while locating play.api.routing.Router for parameter 0 at play.api.http.JavaCompatibleHttpRequestHandler.(HttpRequestHandler.scala:200) while locating play.api.http.JavaCompatibleHttpRequestHandler while locating play.api.http.HttpRequestHandler for parameter 4 at play.api.DefaultApplication.(Application.scala:221) at play.api.DefaultApplication.class(Application.scala:221) while locating play.api.DefaultApplication while locating play.api.Application 1 error

我可以通过在路由文件中添加@来解决这个问题:

POST        /accounts/        @controllers.AccountsController.createOneAccount

但我不确定为什么我需要这样做,以及如何避免“@”。请提出一些建议。

最佳答案

首先,请参阅此答案以了解在您的 routes 文件中使用或不使用 @ 的区别:

https://stackoverflow.com/a/34867199/4600

然后,如 Play 2.5.x migration docs 所述:

Routes are now generated using the dependency injection aware InjectedRoutesGenerator, rather than the previous StaticRoutesGenerator which assumed controllers were singleton objects.

因此,从 Play 2.5.0 开始, Controller 默认使用依赖注入(inject),您不需要 @ 让它们使用依赖注入(inject)。


现在让我们看看您的案例中发生了什么。首先,让我说构造函数注入(inject)是注入(inject)依赖项的首选方式。 Guice 甚至建议(作为最佳实践)将 final 字段与构造函数注入(inject)结合到 minimize mutability . Guice 文档还建议您尝试 inject only direct dependencies .在您的情况下,您正在使用 application 访问 configuration。为什么不注入(inject) configuration 对象呢?这将使您的依赖关系更加清晰(例如,这将使测试更容易)。

因此,按照此建议,您的代码将被重写为:

package controllers;

import com.google.inject.Inject;
import play.Configuration;
import play.mvc.Controller;
import play.mvc.Result;
import services.AccountService;
import java.io.IOException;

public class AccountsController extends Controller {

private final Configuration configuration;
private final AccountService accountService;

private final String host;
private final int port;
private final String dbName;

@Inject
public AccountsController(Configuration configuration, AccountService accountService) {
this.configuration = configuration;
this.accountService = accountService;
// initialize config variables
this.host = configuration.getString("db.default.host");
this.port = configuration.getInt("db.default.port");
this.dbName = configuration.getString("db.default.dbname");
}

public Result createOneAccount() throws IOException {
return accountService.createOneAccount(request().body().asJson());
}
}

但为什么场注入(inject)会中断?

我们首先需要了解对象初始化。根据Java specs :

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

  2. If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.

  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.

  4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.

  5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.

特别注意第 4 步,它解释了您的变量是在对象初始化期间初始化的。

为什么这很重要?因为 Guice 首先创建对象(然后会发生上述所有步骤),然后执行注入(inject)绑定(bind)(有关更多详细信息,请参见 Guice BootstrapGuice InjectionPoints)。因此,在对象初始化时,您的字段需要尚未注入(inject)但会导致 NullPointerException 的变量 (application)。

关于java - Play Framework 2.5.1 路由和依赖注入(inject)(适用于 Java),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36634019/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com