BeanFactoryを使ってみる(Spring1.2RC2)
BeanFactoryはSpringフレームワークの最も基本的な機能を提供するインタフェースらしいので,まずBeanFactoryを使用してみることから始めてみる.
二つのパッケージorg.springframework.beansとorg.springframework.contextは,Springで最も重要なパッケージである.
この二つのパッケージではDI(Depencency Injection)を実現する.
org.springframework.beans.factory.BeanFactoryは,応用的設定メカニズムを提供し,それによって設定ファイルからBeanにマッピングすることができる.
BeanFactoryはさらに基本機能を提供する.
org.springframework.context.ApplicationContextは,BeanFactoryのサブクラスで以下のような機能を追加的に持っている.
ApplicationContextはBeanFactoryの完全なスーパーセットなので,BeanFactoryに関する記述は,ApplicationContextにもあてはまる.
機能的にはBeanFactoryの方がApplicationContextより充実してり,かつApplicationContextはBeanFactoryのスーパーセットなので,どちらを使用すべきか迷ったらAppicationContextを使用すればよい.
ただしメモリ量などの問題が予測されたり,AppicationContextの機能が明らかに不要な場合はBeanFactoryを選択する.
- AOP機能
- 国際化のためのメッセージリソースハンドリング
- イベント伝播
- ApplicationContextやオプションの親コンテキストを作成する宣言メカニズム
- WebApplicationContextなどのアプリケーション層特有のコンテキスト
※ かつてはInversion of Controlと呼ばれていた.
Mediatorパターンなどで,上位から結び付けるクラスを指定したりするのではなく,設定ファイルなどによって,(上位でコーディングすることなく)内側からクラス間を関連づけるパターン.
BeanFactoryは,設定ファイルからbeanを生成してくれる.
したがって,アプリケーションはBeanFactoryに対してbeanを要求する作りになる.
beanのインタフェースをきっておけば,具象クラスが何であるかとか,初期化値などはすべて設定ファイルに追い出すことができる.
とにかくアプリケーションコードから今まで以上に具体的なものを追い出して,変更あるいは拡張に強い作りを目指すことができるようだ.
BeanFactoryを使用するサンプルを作成してみた.
実行方法は以下.
$ tar zxvf HelloBeanFactory-0_01.tar.gz $ ant init $ ant preparelib $ ant run上記preparelibにて依存しているjarも含めたSpringをhttpにてダウンロードする. HTTPプロキシには対応していない. このサンプルを作成する際のポイントは以下であった.
- 設定ファイルを作成する.
- beanクラスを作成する.
- サンプルドライバにてBeanFactoryを生成する.
- サンプルドライバにてBeanFactoryからbeanを取得する.
設定ファイルではbeanの設定,定義を記述する.
サンプルの設定ファイルを以下にしめす.
この設定ファイルではいろいろな設定が可能だが,今回は最も簡単と思われる構成にした.
ポイントを以下に示す.
- ルート要素beans
- 設定ファイルはXMLファイルで,ルート要素はbeansである.
- bean設定要素bean
- beans要素の子要素として各beanの設定にあたる要素beanを記述する.
- beanの属性class
- beanクラスまたはbeanクラスを生成するFactoryクラスのFQCN. このサンプルではbeanクラスを指定した. すなわちSpringはbeanクラス自身のコンストラクタでbeanクラスをインスタンス化する.
- beanの属性id,name
- 属性idはXMLのIDである. これにそぐわないものを設定したい場合は属性nameを使用する. いずれにせよプログラムからBeanFactoryを介してインスタンスを取得するのに使用するので一意でなくてはならない.
- beanの初期化
- 要素beanの子要素propertyにてbeanの初期化指定ができる. 要素propertyの属性nameがフィールド名で,beanはこのフィールド名に基づいたsetterとgetterを持たなければならない. 初期化値にはbeanのネストなどいろいろ指定可能だが,今回はもっとも簡単な,要素valueによる指定値による初期化とした.
より具体的には以下の条件を満たすクラスを作成する.
toStringメソッドは動作確認用(ログ出力用)である.
- 引数のないpublicなコンストラクタを持つ
- 全フィールドにsetterとgetterを持つ. メソッド名はsetXxx,getXxxというパターンにする.
サンプルではBeanFactoryの具象クラスとしてXmlBeanFactoryを使用した.
XmlBeanFactoryはbean設定ファイルを表すResourceオブジェクトを引数にとる.
Resourceの具象クラスには以下がある.
- ClassPathResource
- ClassLoaderにfindResourceしてbean設定ファイルを得る. 今回試した場合にはうまく見付けられなかった. さらにjarファイルからは見付けられないらしい.
- FileSystemResource
- 指定したファイルのパスからbean設定ファイルを得る. ファイルパスが変動するような場合,設定や指定が面倒である.
- InputStreamResource
- bean設定ファイルを何らかの方法でInputStreamとして得る.
- UrlResource
- URLからbean設定ファイルを得る.
- ServletContextResource
- サーブレットコンテキストとパスからbean設定ファイルを得る. 試していない.
URL url = HelloBeanFactory.class.getResource("beans.xml");
Resource res = new UrlResource(url);
BeanFactory factory = new XmlBeanFactory(res);
コメントアウトしているが,FileSystemResource,InputStreamResourceも動作確認できた(前者はしかるべき場所にbeans.xmlを置く必要がある).
BeanFactoryが取得できれば,あとはidやnameによって取得するだけである.
HelloBean helloBeanById = (HelloBean)factory.getBean("helloid");
サンプルのログから指定した値でうまく初期化できていること,beanがsingletonであることが分かる.
2005-05-07 00:20:00,895 INFO [main] xml.XmlBeanDefinitionReader:132 - Loading XML bean definitions from URL [jar:file:/home/matsu/programing/java/spring/dicontainer1/springsample.jar! /org/fireproject/springsample/beans.xml] 2005-05-07 00:20:00,984 INFO [main] springsample.HelloBeanFactory:32 - ====== get HelloBean by id 2005-05-07 00:20:00,990 INFO [main] support.AbstractBeanFactory:219 - Creating shared instance of singleton bean 'helloid' 2005-05-07 00:20:01,122 INFO [main] springsample.HelloBeanFactory:34 - org.fireproject.springsample.HelloBean[messge=Hello Bean!!!!;value=1;] 2005-05-07 00:20:01,123 INFO [main] springsample.HelloBeanFactory:40 - ====== get HelloBean by name 2005-05-07 00:20:01,123 INFO [main] springsample.HelloBeanFactory:42 - org.fireproject.springsample.HelloBean[messge=Hello Bean!!!!!!!!!;value=10;] 2005-05-07 00:20:01,124 INFO [main] springsample.HelloBeanFactory:45 - helloBeanById == helloBeanByName ? true

