t100のプログラミング脱出作戦

自分のプログラミング脳をプログラムにして、いつかプログラミングから脱出してやるぞっ!とか夢見ながら、日々プログラム作っていく 百野 貴博 の日記です!今は、屋号『百蔵。』として、Silverlight・WPFを追跡中です! (2007/09/30)
スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
【--/--/-- --:--】 | スポンサー広告 | トラックバック(-) | コメント(-) top↑
SpringのXMLを何とかオブジェクトで指定できないか考えてみる。
Wicketを使っていて設定ファイル系XMLから開放されつつあるんですが、DIコンテナでSpringを採用したとたんにXMLファイル増加。
他の方のブログで Google Guice という選択肢を見かけたので少し挑戦してみたのですが、トランザクション周りのAOPのさせ方が、もひとつ分からなくて断念。。。(ショボ)

DI/AOP 初心者の自分には、ドキュメントが少ない(日本語のやで)ハードルが越えられませんでした・・・orz

その点、Springであれば、ドキュメントは充実しているので多少安心です。
あとは、XMLを書かないといけないという課題が克服できさえすれば、、、出来さえすれば、、、っ!

というわけで、XMLを使わずにコンフィグを指定する方法を考えてみました。

Spring JavaConfigというのが、まさにピッタシカンカンなんですが、これまたドキュメントの壁にh(略)
■開発方針

Springが参照するXMLファイルは、web.xmlで指定しています。
これらは、Springの起動時にファイルからXML形式で読み込まれています。
あまり大掛かりなものを作りたくないので、この仕組みを上手く利用したいところです。

プログラムで生成した設定内容をSpringに読み込ませられれば目的達成とすると、、、

上記処理中のファイルからXMLを取り出しているところに何とか割り込んで、プログラムで生成したXMLを渡せればいけそうです。
Spring側は割り込まれたとも気づかず、こちらが渡したXMLをファイルから読んだときと同じように処理してくれるってわけですな。
ククク。。。

あとはXMLを生成する処理を上手くオブジェクト化できれば、快適かつ、リファクタリングにも対応した直感的な操作も実現できます。
むほほ。

Springに割り込め

今回、Springは2.0系を使っています。
Springは、web.xml に指定された org.springframework.web.context.ContextLoaderListener というクラスの contextInitialized からスタートします。
今回のソース解析は、ここからスタートしました。

Springの初期化処理は、以下のコンポーネントで構成されています。(デフォルトだと)
※今回の調査に関係ある部分だけです。

ContextLoaderListener : 初期化の開始ポイント。
ContextLoader : 実際の初期化処理の基本になるコンポーネント
XmlWebApplicationContext: Springの状態をXMLから読み込むコンポーネント

ContextLoaderListenerは、ContextLoaderの生成と処理の開始を行っています。
今回の変更とは違いますが、Springの初期化のタイミングを変えたり、ContextLoaderを差し替えたりする場合は、このクラスを変更すれば対応できそうです。

ContextLoaderとXmlWebApplicationContext、は、Springのコンテキストの初期化処理を分担で担当しています。
2つに分かれているのは、Springのコンテキストの記述がXMLのみとは限らないので、記述方式に依存する部分とそれ以外で切り離している為と思われます。
余談ですが、この二つはWebアプリケーションという環境(実行コンテキスト)が前提の作りになっているので、Webアプリケーション以外でSpringを使う場合等は、これらのクラスが入れ換わるのかもしれません。
(未確認ですが)

web.xmlに指定したファイル名を元にファイルを検索して読み込む処理は、XmlWebApplicationContextの中で行っていました。
というわけで、今回はこのクラスを置き換えることにします。


■書き換えはたったの2箇所

XmlWebApplicationContext を継承して処理を置き換えるのは2箇所です。

1.web.xmlに指定した文字列を、Resourceオブジェクトに変換して解析処理に渡しているところ。
2.web.xmlに文字列の指定が無い場合のデフォルトの動作。

1番目は、具体的には loadBeanDefinitions(XmlBeanDefinitionReader reader) というメソッドになります。
既存の処理では、ここでweb.xmlに指定されたファイル名の数分ループしつつ、XMLの解析処理が呼び出されています。
ここで、物理的なファイルを読むのではなく、プログラムで生成したxml文字列を Resourceオブジェクトに変換して解析処理に渡すことにします。

今回は、ざっくり以下のようにしました。
SpringConfig というクラスは、XML生成用に作成した自作クラスです。

@Override
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//親クラスの処理と互換
super.loadBeanDefinitions(reader);

SpringConfig config = new SpringConfig();
//オブジェクトを使ってSpringのコンフィグ設定
...

//XMLに変換。
String xml = configtoXML();

//文字列をリソースに変換して、loadBeanDefinitions メソッドを呼び出し。
reader.loadBeanDefinitions(new ByteArrayResource(xml.getBytes()));
}


2番目ですが、Springは、web.xmlで設定ファイルが指定されていない場合、規定で /WEB-INF/applicationContext.xmlを探しにいき、見つからない場合エラーを発生させてアプリケーションの初期化を失敗させます。
今回の修正ではXMLファイルが無くなる為、ここを上書きしておかないとエラーになってしまいます。

@Override
protected String[] getDefaultConfigLocations() {
return null;
}


これで、プログラムで作成したXMLをSpringに読み込ませる為の修正は終わりです。
ハヤ!

ていうか、こんな簡単なのに説明長すぎっ
(´・ω・`)

■WebApplicationContext を web.xml に登録する。

あとは、今回つくった WebApplicationContext を、web.xml に登録して既存のXmlWebApplicationContextと差し替えれば完成です。
差し替えは、context-param タグを使います。
以下のようになります。


contextClass
net.mekefactory.XmlObjectWebApplicationContext



■以上です。

ふぅぅー。
以上が、Springの設定XMLをオブジェクト化する手順です。

意外と少ない修正で、オブジェクト化への入り口を作成することが出来ました。
まぁ、Springの設定をどうオブジェクト化するか、、、という設計の方が大変なので、しんどくなるのはこれからなのですが、、、


私の場合は、とりあえずHibernateと連携してトランザクションをAOPする記述と、Serviceクラス、Daoクラスの登録だけ出来ればよかったので、その部分だけに対応したオブジェクトを作成しました。
Springの設定ファイルの仕様を全部網羅は出来ないので、、、
これだけでも、クラス名の変更等のリファクタリングに対応出来て便利です。(たぶん)


用途を絞ることで可読性を上げる工夫が出来るので、個人で使う分にはそういう割り切りも良いじゃないかと。。。
ウムウム















管理者にだけ表示を許可する


トラックバックURL:
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。