Spring の Hot Reloding 対応
Spring をベースに Hot Reloding 対応した DI コンテナを Seasar3 としてリリースする.
そんなわけで (どんなわけで?) 随分久しぶりに Spring のソースを見てみたところ...
Spring の DI コンテナの基礎となるのが BeanFactory
.
これは階層構造を持つことが出来ます.
子供の BeanFactory
から getBean()
すると,子供の BeanFactory
に bean がいればそれが返され,いない場合は親の BeanFactory
から bean が返されます.
...というのは嘘です.
BeanFactory
が管理する Bean の情報を持つのが BeanDefinition
.
んで,BeanFactory
は BeanDefinition
を 2 段階で管理しています.
自分自身に定義された bean の BeanDefinition
と,それを親のコンテナに定義された BeanDefinition
とマージした BeanDefinition
すなわち mergedBeanDefinition
です (そういうクラスがあるわけではなく,専ら RootBeanDefinition
というクラスが使われてます).
Spring は bean 定義の継承とかできるからでしょうね.
んで,子供の BeanFactory
に定義がない bean でも,親の BeanDefinition
から mergedBeanDefinition
が作成されます.
そして mergedBeanDefinition
から bean のインスタンスが取得されます.
なので,子供の BeanFactory
から getBean()
すると,元々は子供の BeanFactory
に bean の定義がなくても,子供のコンテナが持つ mergedBeanFactory
から bean が返されるわけ.
だからさっきのは嘘なのね.
当然,BeanFactory
は mergedBeanDefinition
をキャッシュします.
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 したいって人は挑戦してみたらいいんじゃないかな (他人事モード).