作成 2004/10/9
巷で話題のSeasarにさわってみます。
Seasarはオープンソースの国産DIコンテナです。
Seasarプロジェクト
http://www.seasar.org/
DIコンテナの中には、設定ファイルの記述が複雑で、ちょっとしたインジェクションを行うだけでも骨が折れるものがありますが、Seasarは「非常に簡単」に利用することができます。あまり利用されない機能を省き、必要な機能を少ない設定で実現することができます。Seasarは国産のプロジェクトで、ドキュメントが読みやすいのも「簡単」と思える理由の1つかもしれません。
既に分かりやすい日本語ドキュメントがあるので、このページの存在価値はあまりありませんが、まあ、僕もさわってみたよ、ということでメモっときます。
プロジェクトのWebサイトからSeasarをダウンロードします。ここでは現在の最新版のS2.0.22.zipをダウンロードしました。
ダウンロードしたファイルを展開し、libディレクトリの中のJARをクラスパスに通します。全て通してもいいですが、最低限必要なJARは以下になります。
aopalliance.jar asm.jar cglib-2.0.jar log4j-1.2.8.jar ognl-2.6.5.jar s2-framework-2.0.22.jar
Seasarでは、XMLの設定ファイル(diconファイルと呼ばれます)にコンポーネント情報を記述します。
まず次のようなクラス/インターフェイスがあるとします。
IFoo.java
package bean;
public interface IFoo {
void doSomething();
}
Foo.java
package bean;
public class Foo implements IFoo{
private String message = "";
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void doSomething() {
System.out.println("doSomething " + message);
}
}
このクラスをdiconファイルに登録します。ここではbean.Fooクラスをfooという名前で登録しています。初期化時に文字列"Hello"をmessageプロパティーにセットしています。
test.dicon
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
<component name="foo" class="bean.Foo">
<property name="message">"Hello"</property>
</component>
</components>
このfooコンポーネントを呼び出す側は次のようなコードになります。上記設定ファイル、test.diconはクラスパス上のaop/test.diconにあるとします。
package aop;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import bean.Foo;
public class Main {
public static void main(String[] args) {
S2Container container = S2ContainerFactory.create("aop/test.dicon");
Foo foo = (Foo)container.getComponent("foo");
foo.doSomething();
}
}
実行すると以下のように表示されます。
doSomething Hello
コンポーネントの取得は、名前を引数にとる他にクラス(やインターフェイス)を引数にして取得する方法があります。この場合、指定したクラスを継承、実装するコンポーネントが取得されます。
IFoo foo = (IFoo)container.getComponent(IFoo.class);
同じクラスを複数登録する場合もありますが、多くの場合は、単一のクラスを単一のコンポーネントとして登録して、コンポーネント名=完全クラス名とするパターンも多いと思うので、便利な取得手段でしょう。ただし、指定したクラスが複数登録されている場合は、実行時に例外がスローされます。
次に上記のコンポーネントにAOPをかけてみましょう。次のクラスは簡単なMethodInterceptorの実装です。メソッド呼び出しの前後で、before、afterと表示しています。
MyIntercepter.java
package aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MyIntercepter implements MethodInterceptor{
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object result = invocation.proceed();
System.out.println("after");
return result;
}
}
このインターセプターをfooコンポーネントに適用します。diconファイルは次のようになります。doSomethingメソッドにmyIntercepterを適用しています。
test2.dicon
<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components>
<component name="myInterceptor"
class="aop.MyIntercepter"/>
<component name="foo" class="bean.Foo">
<property name="message">"Hello"</property>
<aspect pointcut="doSomething">myInterceptor</aspect>
</component>
</components>
呼び出し側は前の例(Main.java)と同じです(が、diconファイルはaop/test2.diconを読み込みます)。実行すると次のように表示されます。
before doSomething Hello after
あまり利用しないかもしれませんが、diconファイルに登録せずに、Javaコード中でプログラム的にAOPを指定する方法も提供されています。
Pointcut pointcut = new PointcutImpl(new String[]{"doSomething"});
Aspect aspect = new AspectImpl(new MyIntercepter(), pointcut);
AopProxy aopProxy = new AopProxy(Foo.class, new Aspect[]{aspect});
Foo foo = (Foo) aopProxy.create();
Seasarのドキュメント
http://homepage3.nifty.com/seasar/document.html
作ったサンプル(JAR抜き)
s1.zip