Spring の Hot Reloding 対応

Spring をベースに Hot Reloding 対応した DI コンテナを Seasar3 としてリリースする.
そんなわけで (どんなわけで?) 随分久しぶりに Spring のソースを見てみたところ...


Spring の DI コンテナの基礎となるのが BeanFactory
これは階層構造を持つことが出来ます.
子供の BeanFactory から getBean() すると,子供の BeanFactory に bean がいればそれが返され,いない場合は親の BeanFactory から bean が返されます.
...というのは嘘です.


BeanFactory が管理する Bean の情報を持つのが BeanDefinition
んで,BeanFactoryBeanDefinition を 2 段階で管理しています.
自分自身に定義された bean の BeanDefinition と,それを親のコンテナに定義された BeanDefinition とマージした BeanDefinition すなわち mergedBeanDefinition です (そういうクラスがあるわけではなく,専ら RootBeanDefinition というクラスが使われてます).
Spring は bean 定義の継承とかできるからでしょうね.


んで,子供の BeanFactory に定義がない bean でも,親の BeanDefinition から mergedBeanDefinition が作成されます.
そして mergedBeanDefinition から bean のインスタンスが取得されます.
なので,子供の BeanFactory から getBean() すると,元々は子供の BeanFactory に bean の定義がなくても,子供のコンテナが持つ mergedBeanFactory から bean が返されるわけ.
だからさっきのは嘘なのね.


当然,BeanFactorymergedBeanDefinition をキャッシュします.
bean が要求される度に親に問い合わせてマージとかやってられないので.
でもでも,キャッシュしないようにすることもできます.
AbstractBeanFactory には cacheBeanMetadata というフィールドがあって,デフォルトは true でキャッシュするのだけど,false にするとキャッシュしなくなります.
それから,キャッシュした mergedBeanDefinition をクリアする clearMergedBeanDefinition() なんてメソッドもあります.protected だけど.


ということは...

  • コンテナを 2 階建てで構成
  • 親は Hot Reloading 非対象 (mergedBeanDefinition のキャッシュ有効,通常のクラスローダを使用)
  • 子供は Hot Reloading 対象 (mergedBeanDefinition のキャッシュ無効,Hot Reloading 用のクラスローダを使用)

なんてすれば,さほど作り込まなくても Hot Reloading が実現できそうな気配.
あと必要なのは,リクエストの度に <context:component-scan> するわけにはいかないのでオンデマンドで bean を登録する仕掛けとか,Filter あたりでコンテキストクラスローダをごにょごにょするとかって感じかなぁ.


とまぁ,Hot Reloading 対応に必要な仕掛けの中核はもう用意されてしまってる感じ.
そんなわけで (どんなわけで?),Seasar3 に対するモチベーションが萎えてしまいました...
Spring で Hot Reloading したいって人は挑戦してみたらいいんじゃないかな (他人事モード).