Rog*_*ien 5 java playframework playframework-2.5
我在"路线"文件中有这个:
POST /accounts/ controllers.AccountsController.createOneAccount
Run Code Online (Sandbox Code Playgroud)
在我的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());
}
}
Run Code Online (Sandbox Code Playgroud)
这段代码编译得很好,但在运行时我遇到这样的错误:
ProvisionException:无法配置,请参阅以下错误:1)在controllers.AccountsController.(AccountsController.java:11)注入构造函数,java.lang.NullPointerException,
同时在router.Routes中找到参数1的controller.AccountsController.(路由. scala:28)定位router.Routes同时定位play.api.inject.RoutesProvider,同时在play.api.http.JavaCompatibleHttpRequestHandler.(HttpRequestHandler.scala:200)找到参数0的play.api.routing.Router,同时找到play. api.http.JavaCompatibleHttpRequestHandler,同时在play.api.DefaultApplication.(Application.scala:221)的play.api.DefaultApplication.(Application.scala:221)中找到参数4的play.api.http.HttpRequestHandler,同时定位播放.定位play.api.Application 1错误时api.DefaultApplication
我可以通过将@添加到routes文件来解决这个问题:
POST /accounts/ @controllers.AccountsController.createOneAccount
Run Code Online (Sandbox Code Playgroud)
但我不确定为什么我需要这样做,以及如何避免'@'.请提出一些建议.
首先,看看这个答案,了解使用与否的区别@在你routes的文件:
然后,如Play 2.5.x迁移文档所述:
现在使用依赖注入感知生成路由
InjectedRoutesGenerator,而不是先前StaticRoutesGenerator假设的控制器是单例对象.
因此,从Play 2.5.0开始,控制器默认使用依赖注入,您不需要@使用依赖注入.
现在让我们看看你的案例中发生了什么.首先,我要说构造函数注入是注入依赖项的首选方法.Guice甚至建议(作为最佳实践)将final字段与构造函数注入组合以最小化可变性.Guice文档还建议您尝试仅注入直接依赖项.在您的情况下,您正在使用application访问configuration.为什么不注入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());
}
}
Run Code Online (Sandbox Code Playgroud)
我们首先需要了解对象初始化.根据Java规范:
在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:
将构造函数的参数分配给此构造函数调用的新创建的参数变量.
如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用(第8.8.7.1节)开头(使用此方法),则使用这五个相同步骤计算参数并以递归方式处理该构造函数调用.如果该构造函数调用突然完成,则此过程突然完成,原因相同; 否则,继续步骤5.
此构造函数不以同一个类中的另一个构造函数的显式构造函数调用开头(使用此方法).如果此构造函数用于Object以外的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super).使用这五个相同的步骤评估参数并递归处理超类构造函数调用.如果该构造函数调用突然完成,则此过程突然完成,原因相同.否则,继续执行步骤4.
为此类执行实例初始值设定项和实例变量初始值设定项,将实例变量初始值设定项的值按从左到右的顺序分配给相应的实例变量,在这些顺序中,它们以文本方式出现在类的源代码中.如果执行任何这些初始值设定项导致异常,则不会处理其他初始化程序,并且此过程会突然完成同样的异常.否则,继续步骤5.
执行此构造函数的其余部分.如果执行突然完成,则此过程突然完成,原因相同.否则,此过程正常完成.
特别注意第4步,它解释了在对象初始化期间初始化变量.
为什么这很重要?因为Guice首先创建对象(然后将发生上述所有步骤),然后执行注入绑定(有关详细信息,请参阅Guice Bootstrap和Guice InjectionPoints).因此,在对象初始化时,您的字段需要application未注入的variables()导致a NullPointerException.
| 归档时间: |
|
| 查看次数: |
3938 次 |
| 最近记录: |