232

Spring アプリケーションで ApplicationContext のコピーを静的/グローバルに要求する方法はありますか?

メイン クラスがアプリケーション コンテキストを起動して初期化すると仮定すると、コール スタックを介してそれを必要とするすべてのクラスに渡す必要がありますか、またはクラスが以前に作成されたコンテキストを要求する方法はありますか? (シングルトンでなければならないと思いますか?)

4

17 に答える 17

179

コンテナーへのアクセスが必要なオブジェクトがコンテナー内の Bean である場合は、BeanFactoryAwareまたはApplicationContextAwareインターフェースを実装するだけです。

コンテナー外のオブジェクトがコンテナーにアクセスする必要がある場合は、Spring コンテナーに標準の GoF シングルトン パターンを使用しました。そうすれば、アプリケーションにはシングルトンが 1 つだけあり、残りはすべてコンテナー内のシングルトン Bean になります。

于 2008-09-24T21:08:40.613 に答える
127

実装するApplicationContextAwareか、単に使用することができます@Autowired:

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}

SpringBeanApplicationContext注入され、その中でこの Bean がインスタンス化されます。たとえば、非常に標準的なコンテキスト階層を持つ Web アプリケーションがある場合:

main application context <- (child) MVC context

SpringBeanメインコンテキスト内で宣言されている場合、メインコンテキストが注入されます。それ以外の場合、MVC コンテキスト内で宣言されている場合は、MVC コンテキストが挿入されます。

于 2012-05-14T11:31:02.027 に答える
40

これは良い方法です(私のものではありません。元のリファレンスは次のとおりです: http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

私はこのアプローチを使用しましたが、うまく機能します。基本的には、アプリケーション コンテキストへの (静的) 参照を保持する単純な Bean です。春の設定でそれを参照することで、初期化されます。

元の参照を見てください。非常に明確です。

于 2008-09-24T19:33:07.770 に答える
18

SingletonBeanFactoryLocatorを使用できると思います。beanRefFactory.xml ファイルは実際の applicationContext を保持し、次のようになります。

<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
        <list>
            <value>../applicationContext.xml</value>
        </list>
     </constructor-arg>
 </bean>

そして、どこからでも applicationcontext から Bean を取得するコードは次のようになります。

BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("mainContext");
SomeService someService = (SomeService) bf.getFactory().getBean("someService");

Spring チームは、このクラスと yadayada の使用を思いとどまらせていますが、私が使用したところにはよく合いました。

于 2008-09-27T21:43:30.993 に答える
11

他の提案を実装する前に、次の質問を自問してください...

  • ApplicationContext を取得しようとするのはなぜですか?
  • ApplicationContext をサービス ロケーターとして効果的に使用していますか?
  • ApplicationContext へのアクセスをまったく回避できますか?

これらの質問への答えは、特定の種類のアプリケーション (たとえば、Web アプリ) の方が他の場合よりも簡単ですが、とにかく尋ねる価値があります。

ApplicationContext へのアクセスは、依存性注入の原則全体に違反していますが、選択肢があまりない場合があります。

于 2008-09-27T08:28:19.843 に答える
6

Web アプリを使用する場合、サーブレットフィルターと ThreadLocal を使用して、シングルトンを使用せずにアプリケーション コンテキストにアクセスする別の方法もあります。フィルターでは、WebApplicationContextUtils を使用してアプリケーション コンテキストにアクセスし、アプリケーション コンテキストまたは必要な Bean を TheadLocal に格納できます。

注意: ThreadLocal の設定を解除するのを忘れると、アプリケーションをアンデプロイしようとしたときに厄介な問題が発生します。したがって、それを設定してすぐに、最終部分で ThreadLocal の設定を解除する試行を開始する必要があります。

もちろん、これはまだシングルトン、つまり ThreadLocal を使用しています。しかし、実際の豆はもう必要ありません。はリクエスト スコープにすることもできます。このソリューションは、EAR にライブラリがあるアプリケーションに複数の WAR がある場合にも機能します。それでも、この ThreadLocal の使用は、単純なシングルトンの使用と同じくらい悪いと考えるかもしれません。;-)

おそらく、Spring はすでに同様のソリューションを提供していますか? 見つけられませんでしたが、よくわかりません。

于 2009-03-30T14:54:14.817 に答える
5

ContextSingletonBeanFactoryLocatorを見てください。特定の方法で登録されていることを前提として、Spring のコンテキストを取得するための静的アクセサーを提供します。

それはきれいではなく、おそらくあなたが望むよりも複雑ですが、うまくいきます.

于 2008-09-24T19:36:37.980 に答える
4

Spring-test を使用している場合、たとえばシングルトン パターンを使用して、現在のApplicationContext、またはそれ自体の状態を静的変数に保存すると、テストが不安定になり、予測不能になることに注意してください。ApplicationContextこれは、Spring-test が同じ JVM でアプリケーション コンテキストをキャッシュして再利用するためです。例えば:

  1. テスト A の実行で、注釈が付けられ@ContextConfiguration({"classpath:foo.xml"})ます。
  2. テスト B が実行され、注釈が付けられます@ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. テスト C を実行すると、注釈が付けられます@ContextConfiguration({"classpath:foo.xml"})

テスト A が実行されると、が作成され、実装または自動配線ApplicationContextする Beanが静的変数に書き込む可能性があります。ApplicationContextAwareApplicationContext

テスト B を実行すると同じことが起こり、静的変数はテスト B の変数を指すようになります。ApplicationContext

テスト C が実行されると、テスト A の が再利用されるため、Bean は作成されません。これで、現在テスト用の Bean を保持している変数とは別の変数を指す静的変数を取得できました。TestContextApplicationContextApplicationContext

于 2014-02-20T11:52:18.257 に答える
1

シンプルで標準化された方法を使用して、独自のシングルトン Spring Bean への外部アクセスを許可します。この方法で、引き続き Spring に Bean をインスタンス化させます。これが私がすることです:

  1. 外側のクラスと同じ型のプライベート静的変数を定義します。
  2. その変数をthis各クラスのコンストラクターに設定します。クラスにコンストラクターがない場合は、変数を設定する既定のコンストラクターを追加します。
  3. シングルトン変数を返す public static getter メソッドを定義します。

次に例を示します。

@Component
public class MyBean {
    ...

    private static MyBean singleton = null;

    public MyBean() {
        ...
        singleton = this;
    }

    ...
    
    public void someMethod() {
        ...
    }

    ...

    public static MyBean get() {
        return singleton;
    }
}

someMethod次に、コード内の任意の場所で、次の方法でシングルトン Beanを呼び出すことができます。

MyBean.get().someMethod();

すでに をサブクラス化している場合ApplicationContextは、このメカニズムを直接追加できます。それ以外の場合は、これを行うためだけにサブクラス化するか、 にアクセスできる任意の Bean にこのメカニズムを追加してからApplicationContext、それを使用してどこからでも にアクセスできますApplicationContext。重要なことは、Spring 環境に入ることができるのはこのメカニズムであるということです。

于 2021-03-07T00:44:27.287 に答える
0

その点に注意してください; 以下のコードは、既にロードされているものを使用する代わりに、新しいアプリケーション コンテキストを作成します。

private static final ApplicationContext context = 
               new ClassPathXmlApplicationContext("beans.xml");

また、戦争beans.xmlの手段の一部である必要があることにも注意してください。実際のアプリケーションは、言及されている .src/main/resourcesWEB_INF/classesapplicationContext.xmlWeb.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>META-INF/spring/applicationContext.xml</param-value>
</context-param>

コンストラクターでパスを指定するのは困難です。ファイルを見つけることができません。applicationContext.xmlClassPathXmlApplicationContextClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml")

そのため、アノテーションを使用して既存の applicationContext を使用することをお勧めします。

@Component
public class OperatorRequestHandlerFactory {

    public static ApplicationContext context;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }
}
于 2016-12-05T07:44:13.703 に答える