条件に基づいて、異なる Bean を Spring 管理の Bean に自動配線しようとした人はいますか? たとえば、ある条件が満たされた場合、クラス A を注入し、それ以外の場合は B を注入しますか? Google の検索結果の 1 つで、SpEL (Spring Expression Language) で可能であることがわかりましたが、実際の例を見つけることができませんでした。
4 に答える
これを実現するには、複数の方法があります。ほとんどの場合、これは実行したいコンディショニングに依存します。
ファクトリービーン
単純なファクトリ Bean を実装して、条件付き配線を行うことができます。このようなファクトリ Bean には、複雑な条件付けロジックを含めることができます。
public MyBeanFactoryBean implements FactoryBean<MyBean> {
// Using app context instead of bean references so that the unused
// dependency can be left uninitialized if it is lazily initialized
@Autowired
private ApplicationContext applicationContext;
public MyBean getObject() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(applicationContext.getBean(DependencyX.class));
} else {
myBean.setDependency(applicationContext.getBean(DependencyY.class));
}
return myBean;
}
// Implementation of isSingleton => false and getObjectType
}
アプリケーションコンテキストにそのような Bean を 1 つだけ持ちたい場合に備えて、ファクトリ Beanを使用して依存関係 Beanを作成する場合は、おそらくもう少し良いアプローチです。
public MyDependencyFactoryBean implements FactoryBean<MyDependency> {
public MyDependency getObject() {
if (true /* some condition */) {
return new MyDependencyX();
} else {
return new MyDependencyY();
}
}
// Implementation of isSingleton => false and getObjectType
}
スペル
SpEL には多くの可能性があります。最も一般的なのは、システム プロパティベースの条件です。
<bean class="com.example.MyBean">
<property name="dependency" value="#{systemProperties['foo'] == 'bar' ? dependencyX : dependencyY}" />
</bean>
プロパティのプレースホルダー
プロパティのプレースホルダーに Bean 参照を解決させることができます。依存関係の名前は、アプリケーション構成の一部にすることができます。
<bean class="com.example.MyBean">
<property name="dependency" ref="${dependencyName}" />
</bean>
スプリングプロファイル
通常、評価する条件は、Bean のセット全体を登録する必要があるかどうかを意味します。これには、Spring プロファイルを使用できます。
<!-- Default dependency which is referred by myBean -->
<bean id="dependency" class="com.example.DependencyX" />
<beans profile="myProfile">
<!-- Override `dependency` definition if myProfile is active -->
<bean id="dependency" class="com.example.DependencyY" />
</beans>
他の方法で Bean 定義を としてマークすることはできますlazy-init="true"
が、定義はアプリケーション コンテキスト内に登録されたままになります (そして、修飾されていない自動配線を使用すると、作業が難しくなります)。アノテーション@Component
を介してベース Bean でプロファイルを使用することもできます。@Profile
チェックApplicationContextInitialier
(またはこの例) を使用して、プロファイルをプログラムで (つまり、条件に基づいて) アクティブにする方法を確認してください。
Java 構成
これが、Java ベースの構成が非常に人気がある理由です。
@Bean
public MyBean myBean() {
MyBean myBean = new MyBean();
if (true /* some condition */) {
myBean.setDependency(dependencyX());
} else {
myBean.setDependency(dependencyY());
}
return myBean;
}
もちろん、Java ベースの構成でも多かれ少なかれすべての構成メソッドを使用できます ( @Profile
、@Value
または@Qualifier
+を介して@Autowired
)。
ポストプロセッサー
Spring は、アプリケーション コンテキストのライフサイクルに参加できる多数のフック ポイントと SPI を提供します。このセクションでは、Spring の内部動作についてもう少し知識が必要です。
BeanFactoryPostProcessor
s は Bean 定義を読み取って変更できます (たとえば、プロパティ プレースホルダーの${}
解決はこの方法で実装されます)。
BeanPostProcessor
s は Bean インスタンスを処理できます。新しく作成された Bean をチェックして、それで遊ぶことができます (たとえば、@Scheduled
アノテーション処理はこのように実装されます)。
MergedBeanDefinitionPostProcessor
Bean ポスト プロセッサの拡張であり、インスタンス化される直前に Bean 定義を変更できます (@Autowired
注釈処理はこの方法で実装されます)。
2015年10月更新
Spring 4 では、アノテーションを介して条件付き Bean 登録を行う新しいメソッドが追加されました。
@Conditional
それもチェックする価値があります。もちろん、その .xml を介して Spring Boot だけを使用する方法は他にもたくさんあります
@ConditionalOn*
。@Import
また、と(および対応する XML) の両方@ComponentScan
がプロパティ解決を受けることにも注意してください (つまり、 を使用できます${}
)。
最も簡単な方法だと思います:
@Autowired @Lazy
protected A a;
@Autowired @Lazy
protected B b;
void do(){
if(...) { // any condition
// use a
} else {
// use b
}
}
nessassary Bean を宣言しない場合、Spring は実行時にスローしますNoSuchBeanDefinitionException