xbean-springでSpringFrameworkのbeanを JNDIで公開する
フル J2EE コンテナを使わずに SpringFramework だけ利用する場合って、
JNDI を前提にされると結構めんどくさいことがありますよね。
たとえば、UserTransaction を JNDI 経由で取得するのが前提の場合とか。
そんなとき、xbean-spring の SpringInitialContextFactory が便利です。
xbean-spring を使うと、Spring の bean 定義ファイルを元に BeanFactory
を生成し、任意の bean を JNDI 経由で公開することができます。
XBean project
XBean project は、Apache Geronimoのサブプロジェクトらしいです。
http://geronimo.apache.org/xbean/
おいらは maven のリポジトリから xbean-spring の jar を落としてるだけなので、
あまり詳しいことは知りません (^^;
ユーザーのアプリケーションは Spring Framework に依存しません
なんとなく、アプリが Spring に依存するのではという雰囲気をかもし出していますが、
そんなことはありません。
JNDI で Context を公開する仕組みとして Spring が使われているだけなのです。
あくまでも公開側だけです。
ご安心を。
J2EE コンテナが提供する JNDI をルックアップする処理のテストを書くときとか、
いいかもしれない。
SpringInitialContextFactory
さて、いきなり核心に迫ります。
核心は、org.apache.xbean.spring.jndi.SpringInitialContextFactory クラスです。
SpringInitialContextFactory は、InitialContextFactory の実装です。そのため、通常の JNDI の初期化手順を踏むだけで、SpringFramework の bean を JNDI で公開することができます。
こんな例を考えてみた
例。
- InitialContext を new して、
- "key1" というキーに対して "value1" という String を返し、
- "key2" というキーに対して、BeanFactory で生成された bean を返す。
見るからに適当な例ですねw
ソース的にはこんな感じ。
Context ctx = new InitialContext(); System.out.println("ctx.lookup(key1) = " + ctx.lookup("key1")); System.out.println("ctx.lookup(key2) = " + ctx.lookup("key2"));
こんな出力を予定。
ctx.lookup(key1) = value1 ctx.lookup(key2) = java.lang.Object@8fce95
jarの取得
maven なら、こんな感じ。
<dependency> <groupId>org.apache.xbean</groupId> <artifactId>xbean-spring</artifactId> <version>3.4.1</version> </dependency>
最新版はここらへんからチェック
- http://mirrors.ibiblio.org/pub/mirrors/maven2/org/apache/xbean/xbean-spring/
- http://mvnrepository.com/search.html?query=xbean
ということで、この(やる気のなさそうな)例を実現するソースに続く。
ソース
jndi.properties
JNDI関連のプロパティを設定するファイルです。
とりあえずクラスパスに通しておけばOK。(他にもいろいろな方法があるけど)
java.naming.factory.initial=org.apache.xbean.spring.jndi.SpringInitialContextFactory java.naming.provider.url=jndi.xml
jndi.xml
JNDI で公開する Context を構成するための情報を提供する Spring の定義ファイルです。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" > <bean id="value2" class="java.lang.Object" /> <bean id="jndi" class="org.apache.xbean.spring.jndi.SpringInitialContextFactory" factory-method="makeInitialContext"> <property name="entries"> <!-- Entries of the follwing map are to be exported through JNDI --> <map> <!-- String value --> <entry key="key1" value="value1"/> <!-- bean --> <entry key="key2" value-ref="value2" /> </map> </property> </bean> </beans>
Example.java
JNDI のルックアップを行うメインのアプリケーションです。
import javax.naming.Context; import javax.naming.InitialContext; /** * Sample for xbean-spring * * @author beyondseeker@users.sourceforge.jp * @version $Id$ */ public class Example { /** * Sample for xbean-spring * * @param args * N/A * @throws Exception * N/A */ public static void main(String[] args) throws Exception { Context ctx = new InitialContext(); System.out.println("ctx.lookup(key1) = " + ctx.lookup("key1")); System.out.println("ctx.lookup(key2) = " + ctx.lookup("key2")); } }
出力結果
ctx.lookup(key1) = value1 ctx.lookup(key2) = java.lang.Object@8fce95
文字列と任意の bean が公開できました。
ラクチンですね (`・ω・´)
初期化の流れ
Contextの取得方法
普通に、new InitialContext() とかすると、以下のような感じで、コンストラクタ内でいろいろとごにょごにょやってくれます。
InitialContextFactory 実装の特定
InitialContextFactory 実装は、システムプロパティや jndi.properties の java.naming.factory.initial プロパティにて指定されたクラス名のものが採用されます。
ここらへんのルールは、xbean-spring の独自ルールではなく、jndi 共通のルールなので、 javax.naming.Context あたりの javadoc を漁ると情報が転がっています。
SpringInitialContextFactory を使用する場合は、当然ながら、以下のように設定を行います。
java.naming.factory.initial=org.apache.xbean.spring.jndi.SpringInitialContextFactory
※ちなみに、java.naming.factory.initial という文字列は、javax.naming.Context インタフェースの中で、以下のように定義されています。
String INITIAL_CONTEXT_FACTORY = "java.naming.factory.initial";
Context の生成開始
javax.naming.spi.NamingManager から SpringInitialContextFactory#getInitialContext(Hashtable) が呼び出され、シングルトンの Context の生成が開始されます。
SpringFramework の bean 定義ファイルの特定
システムプロパティや jndi.properties の java.naming.provider.url プロパティで指定された文字列からリソースを取得します。文字列は、Springのリソース文字列 (classpath://foo.xml や file://foo/bar.xml や URL) として扱われます。
デフォルトでは、jndi.xml という名前が使用されます。
※ちなみに、java.naming.provider.url という文字列は、javax.naming.Context インタフェースの中で、以下のように定義されています。
String PROVIDER_URL = "java.naming.provider.url";
BeanFactory の生成
上記で特定された SpringFramework の bean 定義ファイルを用いて、BeanFactory が生成されます。
Context の生成
上記で生成された BeanFactory から、"jndi" という id の bean を取得します。(SpringInitialContextFactory クラスの makeInitialContext メソッドをファクトリメソッドとして使用)
※ちなみに、bean の "jndi" という id は、ソース内にべったりと書かれているので、変更できません (´・ω・`)
生成された bean は org.apache.xbean.spring.jndi.DefaultContext クラスのインスタンスで、jndi bean の定義に書かれているプロパティ entries が DI されて返されます。そして、その内容が、Context の内容となります。
簡単ですね (`・ω・´)