scala – 在Play Framework 2.5中使用抽象类和对象进行依赖注入
我正在尝试从Play 2.4迁移到2.5,避免弃用.
我有一个抽象类Microservice,我从中创建了一些对象. Microservice类的一些函数使用play.api.libs.ws.WS来发出HTTP请求,并使用play.Play.application.configuration来读取配置. 以前,我需要的只是一些进口,如: import play.api.libs.ws._ import play.api.Play.current import play.api.libs.concurrent.Execution.Implicits.defaultContext 但现在你should use dependency injection to use 我有类似的东西(缩短): abstract class Microservice(serviceName: String) { // ... protected lazy val serviceURL: String = play.Play.application.configuration.getString(s"microservice.$serviceName.url") // ...and functions using WS.url()... } 对象看起来像这样(缩短): object HelloWorldService extends Microservice("helloWorld") { // ... } 不幸的是,我不明白如何将所有的东西(WS,配置,ExecutionContect)放入抽象类中以使其工作. 我试着把它改成: abstract class Microservice @Inject() (serviceName: String,ws: WSClient,configuration: play.api.Configuration)(implicit context: scala.concurrent.ExecutionContext) { // ... } 但这并没有解决问题,因为现在我也必须改变对象,我无法弄清楚如何. 我试图将对象变成@Singleton类,如: @Singleton class HelloWorldService @Inject() (implicit ec: scala.concurrent.ExecutionContext) extends Microservice ("helloWorld",configuration: play.api.Configuration) { /* ... */ } 我尝试了各种各样的组合,但我没有到达任何地方,我觉得我在这里并没有真正走上正轨. 任何想法如何在不使事情如此复杂的情况下以正确的方式使用WS之类的东西(不使用弃用的方法)? 解决方法
这与Guice如何处理继承更为相关,如果你没有使用Guice,你必须做的就是你要做的事情,Guice是在超类中声明参数并在子类中调用超级构造函数. Guice甚至建议在
its docs:
在纯Java中,它意味着做这样的事情: public abstract class Base { private final Dependency dep; public Base(Dependency dep) { this.dep = dep; } } public class Child extends Base { private final AnotherDependency anotherDep; public Child(Dependency dep,AnotherDependency anotherDep) { super(dep); // guaranteeing that fields at superclass will be properly configured this.anotherDep = anotherDep; } } 依赖注入不会改变它,你只需要添加注释来指示如何注入依赖项.在这种情况下,由于Base类是抽象的,然后不能创建Base的实例,我们可以跳过它并只注释Child类: public abstract class Base { private final Dependency dep; public Base(Dependency dep) { this.dep = dep; } } public class Child extends Base { private final AnotherDependency anotherDep; @Inject public Child(Dependency dep,AnotherDependency anotherDep) { super(dep); // guaranteeing that fields at superclass will be properly configured this.anotherDep = anotherDep; } } 翻译成Scala,我们会有这样的事情: abstract class Base(dep: Dependency) { // something else } class Child @Inject() (anotherDep: AnotherDependency,dep: Dependency) extends Base(dep) { // something else } 现在,我们可以重写您的代码以使用这些知识并避免弃用的API: abstract class Microservice(serviceName: String,configuration: Configuration,ws: WSClient) { protected lazy val serviceURL: String = configuration.getString(s"microservice.$serviceName.url") // ...and functions using the injected WSClient... } // a class instead of an object // annotated as a Singleton @Singleton class HelloWorldService(configuration: Configuration,ws: WSClient) extends Microservice("helloWorld",configuration,ws) { // ... } 最后一点是隐式ExecutionContext,这里有两个选项: >使用default execution context,这将是play.api.libs.concurrent.Execution.Implicits.defaultContext 这取决于您,但您可以轻松注入ActorSystem来查找调度程序.如果您决定使用自定义线程池,则可以执行以下操作: abstract class Microservice(serviceName: String,actorSystem: ActorSystem) { // this will be available here and at the subclass too implicit val executionContext = actorSystem.dispatchers.lookup("my-context") protected lazy val serviceURL: String = configuration.getString(s"microservice.$serviceName.url") // ...and functions using the injected WSClient... } // a class instead of an object // annotated as a Singleton @Singleton class HelloWorldService(configuration: Configuration,actorSystem: ActorSystem) extends Microservice("helloWorld",ws,actorSystem) { // ... } 如何使用HelloWorldService? 现在,您需要了解两件事,以便在需要的地方正确注入HelloWorldService实例. HelloWorldService从哪里获取其依赖项? Guice docs有一个很好的解释:
然后,Playframework为WSClient和Configuration声明了模块.两个模块都为Guice提供了有关如何构建这些依赖关系的足够信息,并且有一些模块可以描述如何构建WSClient和Configuration所需的依赖关系.同样,Guice docs有一个很好的解释:
在我们的例子中,对于HelloWorldService,我们使用constructor injection来启用Guice来设置/创建我们的对象图. 如何注入HelloWorldService? 就像WSClient有一个模块来描述一个实现如何绑定到接口/ trait,我们也可以为HelloWorldService做同样的事情. Play docs有关于如何创建和配置模块的清晰说明,所以我在此不再重复. 但是在创建模块之后,要向控制器注入HelloWorldService,您只需将其声明为依赖项: class MyController @Inject() (service: Microservice) extends Controller { def index = Action { // access "service" here and do whatever you want } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |