![](/img/trans.png)
[英]How to use dependency injection in Scala without Play Framework?
[英]Play Scala Dependency injection: How to use it
我正在尝试使用Play 2.5依赖注入。 我有以下类调用REST api并解析响应
class Client @Inject()(ws:WSClient, baseUrl: string) {
def this(ws:WSClient) = this(ws, "<url string>")
def getResponse() = {....}
....
}
代码的调用者如下所示
var client = new Client(WS.client)
client.getResponse()
我收到了警告。
不推荐使用包ws中的对象WS:将WSClient注入到组件中
我知道我需要注入WS.Client而不是将它显式传递给Client构造函数。 但是我该怎么做?
===更新===
我不想从Controller注入Client或WSClient。 我的控制器在运行时创建对象和类,我希望这些对象创建客户端对象。 当我明确地将WS.client对象传递给Client对象时,我得到上述警告。
===更新2 ===
我的应用程序中有一个插件架构。 当控制器启动一个动作时。 它不知道它将执行哪些插件集。 有些插件不需要WSClient,其中一些插件也是如此。 所以我不想将WSClient的注入耦合到我的控制器中。 每个插件独立决定是否要调用远程服务。 当插件决定调用远程服务时,它应该能够在它想要调用的客户端中注入WSClient。
控制器操作 - >确定要执行的插件 - >执行插件--->插件1(需要调用远程api,创建一个客户端对象,根据新客户端(WS.Client))。 这是注射应该发生的地方,而不是控制器。
好。 我假设你有两节课。 首先,我们将拥有您的Client
类:
@Singleton // this is not necessary, I put it here so you know this is possible
class Client @Inject() (ws:WSClient, baseUrl: String) {
// Since this controller is not annotated with @Inject
// it WILL NOT be used when binding components
def this(ws:WSClient) = this(ws, "<url string>")
def getResponse() = {
// do something using ws object
}
}
然后你有另一个使用Client
类,每个实例,一个控制器:
class MyController @Inject() (client: Client) extends Controller {
def someAction = Action {
// do something with client object
}
}
这里的要点是控制器不需要创建Client
实例。 它由Guice自动注入。
此外,您的客户端类需要一个baseUrl
并且没有地方告诉Play那里需要哪个值。 如果这是一个配置,那么你可以这样做:
import play.api.Configuration
class Client @Inject() (ws:WSClient, configuration: Configuration) {
def getResponse() = {
val baseUrl = configuration.getString("key.to.baseUrl")
// do something using ws object and baseUrl
}
}
但是,如果你真的希望你的Client
对象接收一个String
,那么我们需要告诉Play需要注入哪个String :
package com.acme.modules
import com.google.inject.AbstractModule
import com.google.inject.name.Names
class MyModule extends AbstractModule {
def configure() = {
bind(classOf[String])
.annotatedWith(Names.named("baseUrl")) // attention to the name here. It will be used below
.toInstance("http://api.example.com/")
}
}
然后通过将以下行添加到application.conf
来启用此模块:
play.modules.enabled += "com.acme.modules.MyModule"
之后,我们将更改Client
以了解它所期望的String
:
import play.api.Configuration
// @Named needs to receive the same value defined at the module class.
class Client @Inject() (ws:WSClient, @Named("baseUrl") baseUrl: String) {
def getResponse() = {
val baseUrl = configuration.getString("key.to.baseUrl")
// do something using ws object and baseUrl
}
}
给出你想要/需要的结构:
Controller Action --> Determine Plugins to Execute --> Execute Plugins ---> Plugin1
您的代码也可以使用以下类的路径:
MyController -> PluginResolver -> Plugin
-> PluginRunner ->
然后,你可以:
class MyController @Inject() (
pluginResolver: PluginResolver,
pluginRunner: PluginRunner
) extends Controller {
def action = Action {
val plugins = pluginsResolver.resolve(/* give a criteria to select plugins */)
val someResultFromPluginsExecution = pluginsRunner.run(plugins)
// map result from plugins execution to a play play.api.mvc.Result
// return the play.api.mvc.Result
}
}
import play.api.inject.Injector
class PluginResolver @Inject()(injector: Injector) {
def resolve(/* some criteria to resolve plugins */): Seq[Plugin] = {
val pluginsClasses = ... // find the necessary plugins based on the criteria
pluginsClasses.map { pluginClass => injector.instanceOf(pluginClass) }
}
}
// ExecutionContext is not really necessary, but maybe you want/need
// another thread pool to execute plugins
class PluginRunner @Inject()(implicit executionContext: ExecutionContext) {
def run(plugins: Seq[Plugin]): Seq[PluginExecutionResult] = {
// run the plugins
// return the result
}
}
trait Plugin {
def execute(): PluginExecutionResult
}
这里真正的魔力发生在PluginResolver
。 它使用play.api.inject.Injector
来创建插件实例,然后你的插件可以使用依赖注入。 每个实例:
class PluginThatNeedsWSClient @Inject(wsClient: WSClient) extends Plugin {
def execute(): PluginExecutionResult = {
// Use wsClient to call a remote service
// return the execution result
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.