Spring Framework 入門記 Beanその6 ライフサイクル(インタフェース編)

BigDecimal用のPropertyEditorを作ろうかと思ったのですが,そのあたりは「Reference Docunent」の4章で解説されているようなので,地道に3章を続けることにします.
オブジェクトはライフサイクルを持ちます.生まれて,活動して,捨てられて... そのようなライフサイクルのターニングポイントというのは,必ずしも自身で選択できるものでもありません.志半ばで天に召されることもあります.無念だ((これが書きたかっただけ.(^^;)).
ということで,コンテナはBeanのライフサイクルに関与することが出来ます.といっても,初期化と破棄だけなんですね.Apache AvalonのFrameworkでは,ライフサイクルの様々なイベント(インタフェース)が用意されていたのですが,BeanやPOJOを前提に考えると適用しにくいということなのでしょうか.それにしてもあっさりしすぎで,なんだか物足りなさを感じます.
気を取り直して,Spring Frameworkのライフサイクル管理,まずはインタフェースによる方法から.
初期化のタイミングを必要とするクラスのために,InitializingBeanというインタフェースが用意されています.このインタフェースには,afterPropertiesSet()というメソッドが宣言されています.コンテナ(BeanFactory)は,Beanのインスタンスを生成し,プロパティの設定が終わったタイミングでこのメソッドを呼び出してくれます.
同様に,破棄されるタイミングを必要とするクラスのために,DisposableBeanというインタフェースが用意されています.このインタフェースには,destroy()というメソッドが用意されています.コンテナは,Beanのインスタンスを破棄するとタイミングでこのメソッドを呼び出してくれます.
それにしても,どうしてこう名前が不ぞろいなのでしょう? InitializingBeanDisposableBeanDisposableBeanというインタフェースなのにdestroy()というメソッド.いびつだ... ちなみにAvalon Frameworkでは,Initializable#initialize()Disposable#dispose()です.こっちの方が断然きれいだと思うのですが.
再度,気を取り直してお試しコーナー.
InitializingBeanDisposableBeanimplementsした簡単なクラスを用意します.

package study;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Foo implements InitializingBean, DisposableBean {
    private String text;
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public void afterPropertiesSet() throws Exception {
        System.out.println("initialized.");
    }
    public void destroy() throws Exception {
        System.out.println("destroyed.");
    }
}

そして定義ファイルを用意(<bean>要素だけ抜粋).

    <bean id="foo" class="study.Foo">
        <property name="text"><value>Foo</value></property>
    </bean>

そして実行!

 - Loading XML bean definitions from (no description)
 - Creating shared instance of singleton bean 'foo'
initialized.
foo : study.Foo@15093f1
    text=Foo
    class=class study.Foo

むむ? "initialized."は表示されていますが,"destroyed."って表示がありません.なぜ?
よく考えてみれば,Beanが破棄されるタイミングっていつなのでしょう? 「3.4.1 Lifecycle interfaces」にはドキュメントされていないようです.って,よく考えたらAvalonECM(Excalibur Component Manager)でも,コンテナをdisposeしていたことを思い出しました.Springでも,BeanFactoryを終了してあげればいいのかな.おぉ,destroySingletons()メソッドを発見しました((でもこれ,BeanFactoryのメソッドではなくて,ConfigurableBeanFactoryのメソッドなのですね.このあたりもいずれ...)).
三度,気を取り直して入門記の「その2 setterによるプロパティの設定」で作成した実行用のクラスに以下を追加.

        factory.destroySingletons();

そして実行!!

 - Loading XML bean definitions from (no description)
 - Creating shared instance of singleton bean 'foo'
initialized.
foo : study.Foo@15093f1
    text=Foo
    class=class study.Foo
 - Destroying singletons in factory {org.springframework.beans.factory.xml.XmlBeanFactory defining beans [foo]; Root of BeanFactory hierarchy}
destroyed.

お・っ・け・ー.
destroySingletons()というメソッド名から一目瞭然ですが,これでDisposableBean#destroy()メソッドが呼び出されるのは,そのインスタンスがsingletonの場合だけです.prototypeの場合は呼び出されません.間違いない.
入門記の「Bean その1 id/name属性とsingleton属性」で書いたように,Springでは取得したインスタンスをコンテナに戻さないわけですから,コンテナはそのインスタンスの生涯について関与することはもうできないということですね.無念だ*1
Spring Frameworkのようなコンテナに依存しないBeanやPOJOを組み合わせてアプリケーションを構築したいというような場合,InitializingBeanDisposableBeanimplementsするというのはあまりうれしくないらしいですね.確かに既存のクラスを利用する場合なんかは,アダプタ(ラッパー)みたいなものを作らなきゃいけなくなったりして,いまひとつかもしれません.ということで,次はリフレクション編に進みます.

*1:再度,書きたかっただけです.