Spring アプリケーションで ApplicationContext のコピーを静的/グローバルに要求する方法はありますか?
メイン クラスがアプリケーション コンテキストを起動して初期化すると仮定すると、コール スタックを介してそれを必要とするすべてのクラスに渡す必要がありますか、またはクラスが以前に作成されたコンテキストを要求する方法はありますか? (シングルトンでなければならないと思いますか?)
Spring アプリケーションで ApplicationContext のコピーを静的/グローバルに要求する方法はありますか?
メイン クラスがアプリケーション コンテキストを起動して初期化すると仮定すると、コール スタックを介してそれを必要とするすべてのクラスに渡す必要がありますか、またはクラスが以前に作成されたコンテキストを要求する方法はありますか? (シングルトンでなければならないと思いますか?)
コンテナーへのアクセスが必要なオブジェクトがコンテナー内の Bean である場合は、BeanFactoryAwareまたはApplicationContextAwareインターフェースを実装するだけです。
コンテナー外のオブジェクトがコンテナーにアクセスする必要がある場合は、Spring コンテナーに標準の GoF シングルトン パターンを使用しました。そうすれば、アプリケーションにはシングルトンが 1 つだけあり、残りはすべてコンテナー内のシングルトン Bean になります。
実装するApplicationContextAware
か、単に使用することができます@Autowired
:
public class SpringBean {
@Autowired
private ApplicationContext appContext;
}
SpringBean
がApplicationContext
注入され、その中でこの Bean がインスタンス化されます。たとえば、非常に標準的なコンテキスト階層を持つ Web アプリケーションがある場合:
main application context <- (child) MVC context
SpringBean
メインコンテキスト内で宣言されている場合、メインコンテキストが注入されます。それ以外の場合、MVC コンテキスト内で宣言されている場合は、MVC コンテキストが挿入されます。
これは良い方法です(私のものではありません。元のリファレンスは次のとおりです: http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
私はこのアプローチを使用しましたが、うまく機能します。基本的には、アプリケーション コンテキストへの (静的) 参照を保持する単純な Bean です。春の設定でそれを参照することで、初期化されます。
元の参照を見てください。非常に明確です。
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 の使用を思いとどまらせていますが、私が使用したところにはよく合いました。
他の提案を実装する前に、次の質問を自問してください...
これらの質問への答えは、特定の種類のアプリケーション (たとえば、Web アプリ) の方が他の場合よりも簡単ですが、とにかく尋ねる価値があります。
ApplicationContext へのアクセスは、依存性注入の原則全体に違反していますが、選択肢があまりない場合があります。
Web アプリを使用する場合、サーブレットフィルターと ThreadLocal を使用して、シングルトンを使用せずにアプリケーション コンテキストにアクセスする別の方法もあります。フィルターでは、WebApplicationContextUtils を使用してアプリケーション コンテキストにアクセスし、アプリケーション コンテキストまたは必要な Bean を TheadLocal に格納できます。
注意: ThreadLocal の設定を解除するのを忘れると、アプリケーションをアンデプロイしようとしたときに厄介な問題が発生します。したがって、それを設定してすぐに、最終部分で ThreadLocal の設定を解除する試行を開始する必要があります。
もちろん、これはまだシングルトン、つまり ThreadLocal を使用しています。しかし、実際の豆はもう必要ありません。はリクエスト スコープにすることもできます。このソリューションは、EAR にライブラリがあるアプリケーションに複数の WAR がある場合にも機能します。それでも、この ThreadLocal の使用は、単純なシングルトンの使用と同じくらい悪いと考えるかもしれません。;-)
おそらく、Spring はすでに同様のソリューションを提供していますか? 見つけられませんでしたが、よくわかりません。
ContextSingletonBeanFactoryLocatorを見てください。特定の方法で登録されていることを前提として、Spring のコンテキストを取得するための静的アクセサーを提供します。
それはきれいではなく、おそらくあなたが望むよりも複雑ですが、うまくいきます.
Spring-test を使用している場合、たとえばシングルトン パターンを使用して、現在のApplicationContext
、またはそれ自体の状態を静的変数に保存すると、テストが不安定になり、予測不能になることに注意してください。ApplicationContext
これは、Spring-test が同じ JVM でアプリケーション コンテキストをキャッシュして再利用するためです。例えば:
@ContextConfiguration({"classpath:foo.xml"})
ます。@ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
@ContextConfiguration({"classpath:foo.xml"})
テスト A が実行されると、が作成され、実装または自動配線ApplicationContext
する Beanが静的変数に書き込む可能性があります。ApplicationContextAware
ApplicationContext
テスト B を実行すると同じことが起こり、静的変数はテスト B の変数を指すようになります。ApplicationContext
テスト C が実行されると、テスト A の が再利用されるため、Bean は作成されません。これで、現在テスト用の Bean を保持している変数とは別の変数を指す静的変数を取得できました。TestContext
ApplicationContext
ApplicationContext
シンプルで標準化された方法を使用して、独自のシングルトン Spring Bean への外部アクセスを許可します。この方法で、引き続き Spring に Bean をインスタンス化させます。これが私がすることです:
this
各クラスのコンストラクターに設定します。クラスにコンストラクターがない場合は、変数を設定する既定のコンストラクターを追加します。次に例を示します。
@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 環境に入ることができるのはこのメカニズムであるということです。
その点に注意してください; 以下のコードは、既にロードされているものを使用する代わりに、新しいアプリケーション コンテキストを作成します。
private static final ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
また、戦争beans.xml
の手段の一部である必要があることにも注意してください。実際のアプリケーションは、言及されている .src/main/resources
WEB_INF/classes
applicationContext.xml
Web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>META-INF/spring/applicationContext.xml</param-value>
</context-param>
コンストラクターでパスを指定するのは困難です。ファイルを見つけることができません。applicationContext.xml
ClassPathXmlApplicationContext
ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml")
そのため、アノテーションを使用して既存の applicationContext を使用することをお勧めします。
@Component
public class OperatorRequestHandlerFactory {
public static ApplicationContext context;
@Autowired
public void setApplicationContext(ApplicationContext applicationContext) {
context = applicationContext;
}
}