ファイヤープロジェクト
BeanFactoryPostProcessorとPropertyPlaceholderConfigurer(Spring1.2.1)
2005-07-16T18:45+09:00   matsu
BeanFactoryPostProcessorは,BeanFactoryをインスタンス化した後に,そのインスタンスを引数にとり,何らかの処理をするものである.アプリケーションの起動後の初期化パターンとして使えることがあると思う.BeanFactoryPostProcessorの一つ,PropertyPlaceholderConfigurerは,設定ファイルであるbeans.xmlでの設定値を更に外部プロパティファイルへと移動することが可能な機能を持つらしいので,BeanFacotryPostProcesssorの挙動確認を兼ねて試してみた.
BeanFactoryPostProcessorは,インタフェースであり,以下のメソッドを宣言している.
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
ここで,アプリケーションにBeanFactoryPostProcessorを組み込むというのは,以下の作業を指す.
  1. BeanFactoryPostProcessor具象クラスの作成. あるいはSpringFrameworkにある上記具象クラスの選定. 本頁のサンプルでは,あるいはSpringFrameworkにあるPropertyPlaceholderConfigurerを使用する. この詳細は後述.
  2. BeanFactoryクラスの生成.
  3. 上で作成あるいは生成したBeanFactoryPostProcessorクラスの生成.
  4. BeanFactoryPostProcessorのpostProcessBeanFactoryを呼び出す. 引数は先に生成したBeanFactoryオブジェクトである.
postProcessBeanFactoryメソッド内で何をするかは,各アプリケーション毎の要件による. で,上の手作業でハードコードする手順だと,BeanFactoryPostProcessorはBeanFactory生成後処理の,統一的な仕組みを提供するということ以外にあまり意味はない. ところが,BeanFactoryを拡張したApplicationContextは,上記の作業のいくつかを自動的に行ってくれる. すなわち読み込んだbeans.xmlにBeanFactoryPostProcessorの具象クラスがあればそれを検出,生成し,該当beans.xmlを読み込んだBeanFactoryを引数としてpostProcessBeanFactoryを実行してくれる. BeanFactoryPostProcessor自身もbeans.xmlに記述することで,柔軟に初期化処理のモジュール化やDIが可能となる.
PropertyPlaceholderConfigurerは,beans.xmlに設定シンボルを記述し,そのシンボルに別プロパティファイルのプロパティ値を埋め込む. 以下はPropertyPlaceholderConfigurerを使用する本頁のサンプルのbeans.xmlである.
${...}で記述された部分は,今までならそのまま文字列としてbeanにsetされていたが,PropertyPlaceholderConfigurerの働きにより,プロパティファイルの値に置き換えられる. 例えば,プロパティファイルに
sampleBean.value1=HOGE
とあれば,beans.xmlの
<property name="value1"><value>${sampleBean.value1}</value></property>
という記述は
<property name="value1"><value>HOGE</value></property>
と置き換えられて処理される. この置き換えのタイミングは,PropertyPlaceholderConfigurer#postProcessBeanFactory呼び出し時である.
以下にサンプルのドライバクラスを示す.
BeanPostProcessorのハードコードによる生成と使用は,getBeanFactoryメソッドにて行っている.
XmlBeanFactory factory = new XmlBeanFactory(res);
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("./conf/springsample.conf"));
cfg.postProcessBeanFactory(factory);
BeanFactoryを生成し,BeanFactoryPostProcessorの具象クラスであるPropertyPlaceholderConfigurerをインスタンス化,設定しpostProcessBeanFactoryを呼び出している. ApplicationContextを使用すると,これと同様の処理は以下となる.
XmlBeanFactory factory = new XmlBeanFactory(res);
GenericApplicationContext ctx = new GenericApplicationContext(factory);
ctx.refresh();
今回は,beans.xmlにはSampleBeanFactoryPostProcessorを記述した.
これは,各メソッドの呼び出しタイミングを知るためにログ出力をしている程度で,それ以外は直接PropertyPlaceholderConfigurerを使用するのと変わらない. ApplicationContextは,beans.xmlにBeanPostProcessorの具象クラスであるSampleBeanFactoryPostProcessorが記述されているので,これを自動検知し,インスタンス化し,postProcessBeanFactoryを実行する. ハードコードする方法と,ApplicationContextを使用する方法では,行数は1行しか違わないが,プロパティファイルを外部化している点はもちろん,BeanFactoryPostProcessorの生成,呼び出しそのものを設定ファイル化している点で,ApplicationContextを使用した方法の方がより柔軟で実装も楽ある. 最後にサンプルを実行した際のログを示す. まずハードコード版.
$> java -jar springsample.jar 
springsample.HelloBeanFactory:52 - getBeanFactory start
xml.XmlBeanDefinitionReader:132 - Loading XML bean definitions from URL
  [jar:file:/home/matsu/springsample.jar
   !/org/fireproject/springsample/beans.xml]
config.PropertyResourceConfigurer:154 - Loading properties from file
  [/home/matsu/./conf/springsample.conf]
support.AbstractBeanFactory:219
  - Creating shared instance of singleton bean 'sampleBean'
springsample.SampleBean:12 - setValue1: param = HOGE
springsample.SampleBean:23 - setValue2: param = FUGA
springsample.SampleBean:34 - setValue3: param = FOO
springsample.SampleBean:45 - setValue4: param = BAR
springsample.SampleBean:56 - setValue5: param = 100
springsample.HelloBeanFactory:41
  - org.fireproject.springsample.SampleBean
  [valu1 = HOGE / valu2 = FUGA / valu3 = FOO / valu4 = BAR / valu5 = 100]
次にApplicationContext版.
$> java -jar springsample.jar useApplicationContext 
springsample.HelloBeanFactory:76 - getApplicationContext start
xml.XmlBeanDefinitionReader:132 - Loading XML bean definitions from URL
  [jar:file:/home/matsu/springsample.jar
  !/org/fireproject/springsample/beans.xml]
support.AbstractApplicationContext:289
  - 2 beans defined in application context
  [org.springframework.context.support.GenericApplicationContext;hashCode=20233936]
support.AbstractBeanFactory:219
  - Creating shared instance of singleton bean 'sampleBeanFactoryPostProcessor'
springsample.SampleBeanFactoryPostProcessor:15
  - setLocation of org.fireproject.springsample.SampleBeanFactoryPostProcessor
springsample.SampleBeanFactoryPostProcessor:20
  - postProcessBeanFactory of org.fireproject.springsample.SampleBeanFactoryPostProcessor
springsample.SampleBeanFactoryPostProcessor:21
  - beanFactory = org.springframework.beans.factory.xml.XmlBeanFactory
config.PropertyResourceConfigurer:154
  - Loading properties from file
  [/home/matsu/./conf/springsample2.conf]
...省略...
support.DefaultListableBeanFactory:262 - Pre-instantiating singletons in factory
  [org.springframework.beans.factory.xml.XmlBeanFactory defining beans
   [sampleBean,sampleBeanFactoryPostProcessor];
   root of BeanFactory hierarchy]
support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'sampleBean'
springsample.SampleBean:12 - setValue1: param = HOGE2
springsample.SampleBean:23 - setValue2: param = FUGA2
springsample.SampleBean:34 - setValue3: param = FOO2
springsample.SampleBean:45 - setValue4: param = BAR2
springsample.SampleBean:56 - setValue5: param = 200
springsample.HelloBeanFactory:41
  - org.fireproject.springsample.SampleBean
  [valu1 = HOGE2 / valu2 = FUGA2 / valu3 = FOO2 / valu4 = BAR2 / valu5 = 200]
matsu(C)
Since 2002
Mail to matsu