1

さまざまなモジュールだけでなくカスタム API も含む大規模な Spring ベースのアプリがあります。ドメイン モデルの一部をラップするだけなので、Spring コンテキストを必要とするモジュールがありますが、一部の API はそうではないと考えています。

たとえば、REST サービスを提供および使用するために、Jackson / Jersey のラッパーを作成しました。この API にアクセスするための中央インターフェイスがあります。ただし、実装には別のクラスとその別のクラスが必要です。したがって、単純な初期化は次のようになります

A a = new A(new B(new C(), new D(new E())))

現在、 を使用することから救われてい@Injectます。この API のコンテキストは、パッケージをスキャンしてから、ターゲット アプリにインポートされます。

<import resource="classpath:api-context.xml" />

私たちはこれに満足しておらず、REST ラッパーからスプリング コンテキストを追い出したいと考えています。つまり、API でそれを必要としないようにしたいのですが、それを行う方法がわかりません。次の 2 つのいずれかを意味する必要があります。

コンストラクター引数

ターゲット コンテキストでは、それぞれが依存関係で初期化された複数の Bean を作成する必要があります。

<bean id="a" class="...A">
    <constructor-arg>
        <ref = b " />
    </constructor-arg>
</bean>

<bean id="b" class="...B">
    <constructor-arg>
        <ref = c " />
    </constructor-arg>
</bean>
<!-- And so on -->

ゲッターとセッター

または、それAが の特定の実装でありAInterface、AInterface が中央アクセスであると仮定すると、A はデフォルトで BInterface の特定の実装などを使用し、実際に new で内部的に設定します。

public class A implements AInterface {
    private BInterface b = new B();
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}
// and so on

次に、ターゲット コンテキストで、デフォルト設定を使用する場合は、1 行で中央アクセスを初期化できます

<bean id="a" class="...A" />

または、プロパティを使用して B を設定します。ただし、さらに何かを変更したい場合は、すべての Bean を初期化してプロパティを設定する必要があります。

また、テスト外のサービスに new を使用すると、きれいに見えません。


そのため、他の API 開発者がコンテキスト インポートに依存せずにインターフェイスと Bean にアクセスできるようにする方法を知りたいです (ところで、API が複数のサービスを提供していて、必要なだけの場合など、不要な可能性がある多くの Bean でターゲット コンテキストが乱雑になります)。 1つを使用するには)?


編集

これのいずれかが優れているかどうかはわかりません:

public class A implements AInterface {
    private BInterface b
    public A() {
        b = new B();
    }
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}

また

public class A implements AInterface {
    private BInterface b
    public A(B b) {
        this.b = b;
    }
}

後者はテストの観点からは最高のように感じますが、上記のチェーンに戻り、A を初期化する前にコンテキスト内の依存するすべての Bean を初期化する必要があります。これは構成のオーバーヘッドが多すぎるように感じます。

クラスを使用する前にすべての依存関係を初期化する必要があり、コードをリファクタリングする必要があるのはごく普通のことだと主張する人もいるかもしれません。しかし、多くのユーティリティ/ヘルパー クラスは、置換やテストが難しいため、最適な設計ではありません。

4

2 に答える 2

1

基本的に、API が Spring コンテキストを必要としない場合、そこに配置する理由はまったくありません。

あなたが提案した2番目の方法に注意してください:

public class A implements AInterface {
    private BInterface b = new B();
    public getB() {return b;}
    public setB(B b) {this.b = b) }
}

クラス内でインターフェイスを初期化すると、これらのオブジェクトをモックできないため、テストで問題が発生するため、少し問題があります。より良い解決策は、それを使用するクラスのコンストラクターで初期化することです。

于 2012-07-05T08:53:05.337 に答える
0

デフォルトで遅延ロードするようにすべての Bean を定義するだけで、使用しないサービスをインスタンス化することはありません。

<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>

詳細については、 http://static.springsource.org/spring/docs/2.0.x/reference/beans.html#beans-factory-lazy-initを参照してください。

于 2012-07-05T16:43:39.030 に答える