15

依存性注入、遅延注入の実践からの続き。私はメインクラスを持っています:

package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Scanner;

@Component
public class Main {
    @Autowired
    private StringValidator stringValidator;

    @Autowired
    private StringService stringService;

    @Autowired
    private ValidationService validationService;

    public void main() {
        scanKeyboardCreateLists();

        stringValidator.validate();

        final List<String> validatedList = stringValidator.getValidatedList();
        for (String currentValid : validatedList) {
            System.out.println(currentValid);
        }
    }

    private void scanKeyboardCreateLists() {
        //Let's presume the user interacts with the GUI, dynamically changing the object graph...
        //Needless to say, this is past container initialization...
        Scanner scanner = new Scanner(System.in);
        int choice = scanner.nextInt();

        //Delayed creation, dynamic
        if (choice == 0) {
            stringService.createList();
            validationService.createList();
        } else {
            stringService.createSecondList();
            validationService.createSecondList();
        }
    }

    public static void main(String[] args) {
        ApplicationContext container = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");
        container.getBean(Main.class).main();
    }
}

また、ユーザーの操作に応じて、オブジェクト グラフが動的に作成されます。アプリケーションの結合を解決したので、これを非常に簡単にテストできました。また、リストはコンテナーによって維持されるため、このアプリケーション (およびその他すべて) の動的な性質は、アプリケーションがそれらを必要とするときにいつでも要求でき、その要素を維持できるため、無関係です。

残りのコードは次のとおりです。

package test;

import java.util.List;

public interface Stringable {
    List<String> getStringList();
}

package test;

import org.springframework.stereotype.Component;

import java.util.ArrayList;

@Component
public class StringList extends ArrayList<String> {
}

package test;

import org.springframework.stereotype.Component;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

@Component
public class StringService implements Stringable {

    private List<String> stringList;

    @Inject
    public StringService(final ArrayList<String> stringList) {
        this.stringList = stringList;
    }

    //Simplified
    public void createList() {
        stringList.add("FILE1.txt");
        stringList.add("FILE1.dat");
        stringList.add("FILE1.pdf");
        stringList.add("FILE1.rdf");
    }

    public void createSecondList() {
        stringList.add("FILE2.txt");
        stringList.add("FILE2.dat");
        stringList.add("FILE3.pdf");
        stringList.add("FILE3.rdf");
    }

    @Override
    public List<String> getStringList() {
        return stringList;
    }
}

package test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class StringValidator {
    private List<String> stringList;
    private List<String> validationList;

    private final List<String> validatedList = new ArrayList<String>();

    @Autowired
    public StringValidator(final ArrayList<String> stringList,
                           final ArrayList<String> validationList) {
        this.stringList = stringList;
        this.validationList = validationList;
    }

    public void validate() {
        for (String currentString : stringList) {
            for (String currentValidation : validationList) {
                if (currentString.equalsIgnoreCase(currentValidation)) {
                    validatedList.add(currentString);
                }
            }
        }
    }

    public List<String> getValidatedList() {
        return validatedList;
    }
}

package test;

import java.util.List;

public interface Validateable {
    List<String> getValidationList();
}

package test;

import org.springframework.stereotype.Component;

import java.util.ArrayList;

@Component
public class ValidationList extends ArrayList<String> {
}

package test;

import org.springframework.stereotype.Component;

import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;

@Component
public class ValidationService implements Validateable {

    private List<String> validationList;

    @Inject
    public ValidationService(final ArrayList<String> validationList) {
        this.validationList = validationList;
    }

    //Simplified...
    public void createList() {
        validationList.add("FILE1.txt");
        validationList.add("FILE2.txt");
        validationList.add("FILE3.txt");
        validationList.add("FILE4.txt");
    }

    public void createSecondList() {
        validationList.add("FILE5.txt");
        validationList.add("FILE6.txt");
        validationList.add("FILE7.txt");
        validationList.add("FILE8.txt");
    }

    @Override
    public List<String> getValidationList() {
        return validationList;
    }
}

メソッド呼び出し createList() または createSecondList() を解決する方法を知っている人はいますか?設計をほとんど強制するコンストラクターを使用しません。私はファクトリを考えていましたが、より大きな規模のプロジェクトのすべてのクラスのファクトリは良い考えではないようです。

何かのようなもの:

<bean ... factory-method="..." depends-on="..." lazy-init="..."/>

そして、ファクトリ メソッドでクラスをインスタンス化し、メソッド createList() を呼び出します。または、何らかのメソッドからこのように呼び出します。これも見栄えが悪く、オブジェクト グラフをインスタンス化する責任をメソッドに負わせます。

実行時に解決したい実行時の依存関係の図は次のとおりです。

ここに画像の説明を入力

ユーザーの操作に応じてコンテナを使用して動的な遅延初期化を実現する方法は他にありますか?

ありがとうございました。

4

3 に答える 3

10

クラスの一部のメンバーを、対応するゲッターへの呼び出しごとに動的に初期化/設定したい場合は、ルックアップ メソッド インジェクションを試すことができます。pp. 3.3.4.1を こちらでお読みください。

したがって、動的メンバーを含むクラスがscope=singletone(Spring Bean コンテナーのデフォルト) で作成された場合でも、ルックアップ メソッドが割り当てられたフィールドにアクセスするたびに、ルックアップ メソッド内に実装されたビジネス ロジックに従って適切なオブジェクトが取得されます。 . あなたの場合、リストはインターフェースであるため、ルックアップメソッド内に検証を簡単に実装して、検証済みのリストを返すことができます。

編集:

Springのドキュメントでより良い例を見つけました-非常に明確だと思います。「3.4.6.1 Lookup メソッドのインジェクション」を参照してください。

クラスを構成するときMainに、ルックアップ メソッドをそのメンバーに割り当てます。これは、 BeanListの新しいインスタンスが必要になるたびに呼び出されます。List

幸運を!

于 2012-05-07T14:35:11.103 に答える
3

Spring は、ビジネス データの操作と注入用ではなく、再利用可能なコンポーネントの注入用に設計されています。

実際、一部のデータは依存性注入で使用されますが、コンポーネントの動作を構成するためだけであり、ビジネス データ ホルダーを作成するためではありません。

ちなみに、あなたのケースでは次のオプションを使用できます: BeanFactoryAware インターフェースと scope="prototype" の使用に感謝します。その例のように、または他の質問から呼び出して Bean を生成できますBeanFactory:オンデマンドでBean を作成する.getBean()

準備する Bean の数が限られている場合の代替オプションは、不足している Bean がモックされるのと同じ方法で汎用 Bean の作成を使用することです

ここで、Spring がそのコンテキストで Bean をガベージ コレクションしないことを考慮してください。そのため、Spring Bean を作成してビジネス データを保持することは、メモリを消費するリスクがあります。

目的が異なる場合 (そうであることを願っています)、マルチテナント サポートを独自に実装しようとしている可能性があります。Spring は、特定のコンポーネントまたは動作で実装する異なるビジネス コンテキストがある場合にテナンシーを提供します。

于 2012-05-11T19:37:31.463 に答える
2

ユーザーは 1..N 個のオブジェクトのグラフを選択でき、実行時にユーザーが選択したグラフのみをロードしたいようです。設計時にグラフがわかっているが、ユーザーが必要なものを選択するだけの場合、あなたが持っているのは ApplicationContexts の束であり、ユーザーが実行時に選択した 1 つの ApplicationContext のみをロードしたいように思えます。では、ApplicationContext のセットを定義してから、実行時に適切なものをインスタンス化するだけではどうですか。Spring は Java Config をサポートしているため、これらの構成を Java クラスとして定義して、継承を取得し、コードの切り取りと貼り付けを回避できるようにすることは理にかなっています。

于 2012-05-10T00:53:58.150 に答える