5.DIされたときの動作の
制御(カスタマイズ)について
概要
ここまでの記事で、Springの設定の記述方法を最新のSpring3.0の機能を含めて見てきました。
この記事では、SpringのDIコンテナがbeanを読み込むときの動作のカスタマイズ方法を見て行きます。
実は、いろいろなイベントを制御できますので、カスタマイズが容易です。
目次を見ながらどんなことができるか確認してみてください。
beanを生成した後の動作の制御(InitializingBean)
XML上に、beanタグで記述されたクラスはDIコンテナが勝手にインスタンスを作ってくれます。
このとき生成後に必ず行いたいことがある場合があります。
例えば生成後つまり、new して、プロパティ(setter)に値がセットされた後でないと、必須の値が入っているかをチェックできません。
しかし、このような妥当性チェック用のメソッドを作り、applicationContext.getBean()した後に毎回呼ぶのは効率的ではありません。
そんなときにはInitializingBeanインターフェースをimplementsします。
【InitializingBeanのサンプル】
public class DbObject implements InitializingBean{
private DataSource dataSource;
//accessor---------------------------------------------
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "dataSource must not be null.");
}
}
InitializingBeanがimplementsされると、SpringのDIコンテナはbeanを生成しプロパティがセットされた後にafterPropertiesSet()メソッドを呼び出します。
上記の例では、SpringのAssertクラスを使用してDataSourceがnullかどうかをチェックしています。
nullの場合は、IllegalArgumentExceptionが発生します。
この機構を使うと、妥当性チェックだけでなくクラスの初期化など、いろいろなことができます。
ただ、SpringのDI上で動作する機構ですので、例えば上のクラスを自分でnewした場合は、
afterPropertiesSet()メソッドが呼び忘れたりする可能性があることは考慮に入れておかないといけません。
クラス内で他のbeanを使いたい場合の制御(BeanFactoryAware)
Spring上の他のbeanを自動的に操作したい場合があるかもしれません。
他のbeanを操作するには、まずは他のbeanを自分のクラスで受け取らなければいけません。
通常であれば、他のbeanを受け取るには、必ずプロパティでそのbeanをセットしてもらいます。
ここではそのようなことをせずに他のbeanを受け取る方法を見てみます。
【BeanFactoryを受け取り、他のbeanを操作する例】
public class SpringOperationSample implements BeanFactoryAware, InitializingBean {
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
@Override
public void afterPropertiesSet() throws Exception {
//何か操作します
Bean1 b1 = this.beanFactory.getBean("bean1");
b1.execute();
}
}
BeanFactoryAwareをimplementsすると、SpringのDIコンテナが自動的にBeanFactoryをsetterにセットしてくれます。
あとはクラス内でBeanFactoryを利用してbeanを取得して操作をすればよいだけです。
上記の例では、InitializingBeanとあわせて使用しています。
他にもいろいろ利用できるかと思います。
ただ、このインターフェースを利用するとSpringのクラスにかなり依存することになりますので、SpringのDIコンテナ操作専用のクラスとして
クラスを設計した方が良いかと思います。
上記の例を見ても分かりますように、普通に setBean1(Bean1 bean1) を用意してDIしても同じことができます。
このインターフェースは通常では使用する必然性がかなり低いです。
使用に際しては本当にこの機構を使用しなければできないことか、をよくお考えの上お使いいただければと思います。
ApplicationContextロード時の制御(BeanFactoryPostProcessor)
beanが生成される前、すなわちApplicationContextのロード時点で何か処理をしたい場合があるかもしれません。
例えば、あるクラスのstaticなフィールドの初期化などは、ロード時にしておきたいかと思います。
そのような場合の制御方法を見てみましょう。
【ApplicationContextのロード時点で何か処理をさせるサンプル】
public class PathSetPostProcessor implements BeanFactoryPostProcessor {
private String path;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException {
//staticなメソッドに初期値を設定してみます。
Sample.setPath(this.path);
}
public void setPath(String path) {
this.path = path;
}
}
BeanFactoryPostProcessorをimplementsすると、SpringのDIコンテナがこのクラスを自動的に見つけ出し、他のbeanより先に生成し、
postProcessBeanFactory()メソッドを呼び出してくれます。
【Spring設定ファイル上の設定サンプル】
<bean class="my.PathSetPostProcessor">
<property name="path" value="c:/temp"/>
</bean>
上記のように、pathプロパティ(setter)をXML上で設定していれば、それが設定された後にpostProcessBeanFactory()メソッドが呼ばれます。
これも使いどころが色々あると思います。
ただ、このインターフェースについても、SpringのDIコンテナ操作専用のクラスとしてクラスを設計した方が良いかと思います。
使い方にお気をつけください。
Created Date: 2011/11/01