2016-04-18 4 views
4

私はPlay 2.5依存性注入を使用しようとしています。私は、REST APIへの呼び出しを行うと、コードの呼び出し側が、私は次の警告を取得しています Play Scala依存性注入:使用方法

var client = new Client(WS.client) 
client.getResponse() 

の下のようになります。応答に

class Client @Inject()(ws:WSClient, baseUrl: string) { 

    def this(ws:WSClient) = this(ws, "<url string>") 
    def getResponse() = {....} 
.... 

} 

を解析するクラスを次のようしています。パッケージWSで

オブジェクトWSは廃止されました:ジェクトWSClientをご コンポーネント

に私はクライアントのコンストラクタに明示的に渡すのではなく、WS.Clientを注入する必要があることを理解しています。しかし、どうすればいいのですか?

=== ===更新

私はコントローラーからクライアントまたはWSClientを注入する必要はありません。私のコントローラは、実行時にオブジェクトとクラスを作成し、これらのオブジェクトでClient Objectを作成します。 WS.clientオブジェクトをClientオブジェクトに明示的に渡すと、上記の警告が表示されます。

===アップデート2 ===

私は自分のアプリケーションにプラグインアーキテクチャを持っています。コントローラがアクションを開始するとき。どのプラグインが実行されるのかはわかりません。いくつかのプラグインはWSClientを必要とせず、その中にはいくつかのプラグインがあります。だから私はWSClientの注入を私のコントローラーに結合したくありません。各プラグインは、リモートサービスを呼び出すかどうかを独自に決定します。プラグインがリモートサービスを呼び出すことを決定すると、プラグインはクライアントが呼び出したいクライアントにWSClientを注入できます。

コントローラアクション - >実行するプラグインを決定する - >プラグインを実行---> Plugin1(リモートAPIを呼び出し、新しいクライアント(WS.Client)というクライアントオブジェクトを作成する必要があります)。これはコントローラではなく、注入が行われる場所です。

+0

警告が表示されているコードを表示します。 'WS'の代わりに' WSClient'を使用していますか? – marcospereira

+0

新しいクライアント(WS.client)行に警告が表示されています。私の質問は、注入されたWSClient @marcospereiraを使用する方法です。 – konquestor

+0

この呼び出し元は、プロジェクト内のテストまたは他の通常のクラスですか?依存関係注入を使って 'Client'を作成してバインドする理由はありますか? – marcospereira

答えて

5

私はあなたに2つのクラスがあると仮定します。まず、あなたの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 
    } 

} 

ここでの主なポイントは、コントローラを作成する必要はありませんでしたということですa Clientインスタンス。それはGuiceによって自動的に注入されました。

また、クライアントクラスにはbaseUrlが必要で、そこにはどの値が必要かをプレイに伝える場所はありません。これは、あなたがこのような何かができるより設定の場合:あなた本当にがにあなたのClientオブジェクトがStringを受けたい場合は、

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 
    } 
} 

をしかし、我々はtell Play which String needs to be injectedする必要があります。

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" 
質問の編集後

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 

は、あなたが/必要したい構造を与えるとその後

、我々はそれを期待しているStringどの程度具体的にはClientを変更しますあなたのコードは、次のようなクラスでそのパスをたどることもできます:

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 
    } 
} 

プラグインクラス:

本当の魔法がここ PluginResolverで行わ
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 
} 

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 
    } 
} 

参考:

  1. Scala: Dependency Injection
  2. Scala: Play WS API
  3. play.api.inject.Injector
+1

ありがとうございます。しかし、私はコントローラからクライアントまたはWSClientを注入したくありません。私のアプリデザインは、どのオブジェクトが作成されるかを動的に決定します。私はクライアントオブジェクトをコントローラから、コントローラが作成したすべてのオブジェクトに渡したくない。私はコントローラからクライアントを注入せずにWSClientを注入できますか? – konquestor

+0

上記の説明をユースケースに適応させることができます。 Clientオブジェクトが作成されたWSClientを挿入し、 'new Client(WS.client)'の代わりに 'new Client(myInjectedWSClient)'を実行してください。 – marcospereira

+1

myInjectedWSClientはどこから注入されますか?コントローラー?私はコントローラに依存関係を注入したくない。 – konquestor

関連する問題