1

私の現在のプロジェクトでは、巨大なインターフェースを実装する EJB を扱っています。実装は、同じインターフェイスを実装し、実際のビジネス コードを含むビジネス デリゲートを通じて行われます。

のようないくつかの記事で示唆されているように

この「コマンドパターン」の使用順序は、

  1. クライアントはコマンドを作成し、それをパラメータ化します
  2. クライアントはコマンドをサーバーに送信します
  3. サーバー受信コマンド、ログ、監査、およびアサートコマンドを提供できます
  4. サーバー実行コマンド
  5. サーバーはコマンドの結果をクライアントに返す

問題はステップ 4 で発生します。

現在、コマンド内のコンテキストから Bean を取得するためにスプリング コンテキストを使用していますが、依存関係をコマンドに注入したいと考えています。

以下は、説明のための単純な使用法です。問題がある場所にコメントを追加しました。

public class SaladCommand implements Command<Salad> {    
    String request;

    public SaladBarCommand(String request) {this.request = request;}

    public Salad execute() {    
        //this server side service is hidden from client, and I want to inject it instead of retrieving it
        SaladBarService saladBarService = SpringServerContext.getBean("saladBarService");       
        Salad salad = saladBarService.prepareSalad(request);       
        return salad;
    }
}

public class SandwichCommand implements Command<Sandwich> {    
    String request;

    public SandwichCommand(String request) {this.request = request;}

    public Sandwich execute() {  
        //this server side service is hidden from client, and I want to inject it instead of retrieving it      
        SandwichService sandwichService = SpringServerContext.getBean("sandwichService");       
        Sandwich sandwich = sandwichService.prepareSandwich(request);       
        return sandwich;
    }
}

public class HungryClient {
    public static void main(String[] args) {
        RestaurantService restaurantService = SpringClientContext.getBean("restaurantService");
        Salad salad = restaurantService.execute(new SaladBarCommand(
            "chicken, tomato, cheese"
        ));
        eat(salad);

        Sandwich sandwich = restaurantService.execute(new SandwichCommand(
            "bacon, lettuce, tomato"
        ));
        eat(sandwich);
    }
}

public class RestaurantService {
    public <T> execute(Command<T> command) {
        return command.execute();
    }
}

SandwichService sandwichService = SpringServerContext.getBean("sandwichService"); のような呼び出しを取り除き、代わりにサービスを注入したいと考えています。

それを最も簡単な方法で行う方法は?

4

6 に答える 6

3

DIがどのように機能するかを理解することは問題ではありません

私はこの同じケースに出会うので、ギヨームに同意します。

主な問題は、インスタンス化とオブジェクトのライブサイクルです。

  1. コマンドは何度でも作成できますが、たとえば同じ方法です。そしてプログラムで。

  2. コンテナとしてのSpringは、スコープ(セッション、プロトタイプ=スレッドスコープ)、アプリケーションスコープを使用してオブジェクトを1回作成することを前提としています...

したがって、コマンドはspringによる作成ではなく、springによって作成されたサービスを使用する必要があります。ただし、サービスはコマンドに挿入されません。

ありがとうございました

于 2011-06-10T09:38:35.890 に答える
3

サーバー側の RestaurantService で、次の操作を行います。

  1. ApplicationContextAware インターフェースを実装します。これにより、Spring はアプリケーション コンテキストへの参照を RestaurantService に挿入します。

  2. RestaurantService.execute(Command) メソッドで、次のようにします。

    AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
    beanFactory.autowireBeanProperties(command, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
    command.execute();
    
  3. 最後に、アプリケーション コンテキストで、依存関係が注入された各 Command オブジェクトのインスタンスを宣言します。

これにより、クライアントでオブジェクトを作成し、シリアル化し、サーバーに送信し、使用する前に依存関係を注入できるようになります。オブジェクトを使用する直前ではなく、オブジェクトを受け取ったときに注入を行う方がクリーンな場合があります。

AutowireCapableBeanFactory の使用方法には、他にもいくつかのオプションがあります。この例では、適切なクラスを持つ Bean 定義を検索し、アプリ コンテキストで定義されたプロパティを設定します。各 Command 実装をアプリ コンテキスト内の名前に関連付けることができる場合は、代わりに、コールバックをサポートする configureBean(Object, String) を使用できます。

于 2013-09-11T15:48:50.870 に答える
1

あなたが現在行っているようなコマンドパターンを使用しなかったことを除いて、私は過去に驚くほど似たものを構築しました. あなたの場合、コマンドは実際にサービス メソッドを検索して実行するだけのように見えるので、コマンド パターンを完全に使用する代わりに、単にそのサービス メソッドを API として提示しないでください。次に、Spring Remoting を介してサービス呼び出しを EJB に関連付けることができます。Spring のすべての仕様は、プロトコル固有のレイヤー (サーブレット、EJB、MDB ...) にとどまることができ、コードはその周りで何が起こっているかを驚くほど無視したままになります。 .

私たちのインフラストラクチャは次のようになります。(EJB の存在について不満を言う人のために説明すると、これはインフラストラクチャ全体ではありません。セキュリティとパフォーマンスの理由から、サービス間の対話には EJB から EJB 呼び出しを使用します)。

Eclipse リッチ クライアント -> (Spring Remoting - HTTP) -> サーブレット -> (ローカル インターフェイス) -> EJB -> サービスの実装

サーブレット - Spring コンテキストを使用してローカル EJB インターフェースをルックアップし、RemoteInvocation オブジェクト (Spring Remoting から HttpProxyFactoryBean によって生成および送信される) およびサービス インターフェースの名前を使用して、汎用 EJB インターフェースの共通呼び出しメソッドを呼び出します。

EJB - インターフェイス名 (Bean 名でもあります) に基づいてサービスを検索し、RemoteInvocationExecutor を使用して、RemoteInvocation オブジェクトでサービス実装のメソッドを呼び出します。

これで、EJB を複数のサービスに関連付けることができます (ただし、1 対 1 の配置モデルを使用します)。Spring Remoting は、さまざまなアプリケーションからサービスへの Http、EJB、または JMS ベースの呼び出しに使用できます。テストを実装に直接接続するだけなので、サーバーをデプロイせずにテストするのは簡単です。

注: 機会があれば、いくつかのコード スニペットを追加しようとします。

于 2010-01-26T16:00:45.363 に答える
0

SimpleCommand が Spring ApplicationContext によってそれを使用してクラスに注入されている場合 (実際にはそうあるべきです)、単純にその依存関係をコンストラクター引数またはセッターとして表現し、それらも注入する必要があります。

誰が SimpleCommand を使用しているのか、どこから来たのかなどを理解せずに、これ以上詳細を説明することは困難です。

于 2010-01-26T15:43:07.510 に答える
0
public class SampleCommand implements Command {    
    private final String parameter;
    private final ServiceBean service;

    //the client build the command using a parameter
    public SampleCommand(ServiceBean service, String parameter) {
         this.parameter = parameter;
         this.service = service;
    }

    //this code will be executed by the server
    public Object execute() {
        //do something using the parameter and return the result
        return service.doSomethingWith(parameter);            
    }
}

Spring の有無にかかわらず、サービスを注入できます。

<bean id="sampleCommand" class="package.SampleCommand">
     <constructor-arg ref="serviceBean" />
     <constructor-arg value="Param" />
</bean>

一部の通話アプリ:

ServiceBean service = ServiceProxy.getService(SampleCommand.class);
Command command = new SampleCommand(service, "Param");

依存性注入はフレームワークに依存しません。

于 2010-01-26T16:38:39.100 に答える