新トップページへ | Tip
Seasar2のDI/AOP機能を使う
LastUpdate : 12/03/10
Seasar2を使い、DI機能とAOP機能の使い方について調べたことをメモしたものです。
基本的に情報源は公式ページ(http://www.seasar.org/)を参考にしています。
Seasar2.3と2.4を対象としています。
すべての情報は網羅してません。基本事項を抑える程度のまとめです^^;
目次
- 基本
開発環境(前提環境)+基本的な説明
- DIについて
- 最も基本的なソース
- DIするオブジェクトの初期化(基本)
- DIするオブジェクトの初期化(詳細)
フィールドインジェクションについて
diconファイルの分割について
- AOPについて
- 基本的な話
TraceInterceptorの使用例
ThrowsInterceptorの使用例
独自のInterceptorの作り方について
- 実際に使用するに当たって
- コンポーネントの自動登録
暗黙的なコンポーネント
開発環境について
Eclipseで、ソースを記述し、Eclipseからテスト起動を行い、動作確認をすることを目的としています。
以下の環境で作成しました。
Windows7(64bit)上で動かしながら、ここのページのソースを作成。
Eclipse |
: |
3.7 |
Seasar |
: |
Seasar2 2.4.45 |
JDK |
: |
SUN ビルド1.7.0_01-b08 |
本ページの前提事項
Seasarの公式ページを見るとわかりますが、いろいろなプロダクトがあります。
DIとAOP機能を提供するプロダクト、JSFを使って画面表示機能を提供するプロダクト、DBアクセス機能を提供するプロダクト・・・。いろいろあります。
これらのプロダクトから、使いたいものだけを使って、アプリを開発することになるかと思います。
今回はDI/AOPがターゲットなので、「Seasar2 (S2Container)」しか利用しません。
基本的にWeb画面などは無く、すべてmainメソッドを使いそこから実行することを前提とします。
プログラムを開発する上での、環境構築は、まぁてきとーにw
このページを作成するにあたって、以下の手順で環境構築しました。
(1) 公式ページより、以下2つをダウンロード
・S2Container 2.4.45
・S2Tiger 2.4.45
(2) 解凍して、jarファイルを設定ファイル(diconファイルなど)をEclipseのプロジェクトへコピペ
(3) Eclipse側で、jarや設定ファイルにパスを通す
とりあえず、jarと設定ファイルにパスが通っていれば問題ないかと思います。
以下のような、javaファイルを3つ、diconファイルを1つ作成しました。処理の流れは以下のような感じです。
(1) インターフェイスクラスとその実装クラスを作成し、それをdiconファイルに記述
(2) Seasarから提供されるクラスであるS2CotainerFactoryに、設定ファイル(diconファイル)を読み込ませDIコンテナの初期化
(3) DIコンテナへ名前を渡すと、DIコンテナ内部で処理が行われ、インスタンスを戻り値として返す
この(3)の「DIコンテナ内部で処理」という部分を、以降サンプルで例示していきます。
ちなみに、DoWork work2 = (DoWork)container.getComponent(DoWork.class); とやってインターフェイスクラスを引数に渡してやる方法では、diconファイル内に、DoWork.classを継承するクラスが複数ある場合、Seasarから例外が飛びます。
DoWork.classを継承したクラスを探しに行ったら複数ある・・・どっちを使えばいいんじゃー!ということになって、判断できないので、GiveUpして例外が飛ぶわけです。
EntryPoint.java(このファイルをスタートポイントとします) |
package sample2;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* 最も基本的なサンプル
*/
public class EntryPoint {
public static void main(String[] args) {
String path = "sample2/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
// componentタグのname属性で指定した名前で、インスタンスを取得する
DoWork work1 = (DoWork)container.getComponent("doWork");
work1.doWork();
// そのほか、以下のように、クラスを直接指定することも可能
DoWork work2 = (DoWork)container.getComponent(DoWork.class);
work2.doWork();
DoWork work3 = (DoWork)container.getComponent(DoWorkImpl.class);
work3.doWork();
System.out.println("------------- finish -------------");
}
}
|
DoWork.java |
package sample2;
public interface DoWork {
public void doWork();
}
|
DoWorkImpl.java |
package sample2;
public class DoWorkImpl implements DoWork {
public void doWork() {
System.out.println("DoWorkImpl#doWork()だよ!");
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component name="doWork" class="sample2.DoWorkImpl"/>
</components>
|
■実行結果(コンソール出力) |
------------- start -------------
DEBUG 2012-02-19 19:01:27,739 [main] S2Containerを作成します。path=sample2/sample.dicon
DEBUG 2012-02-19 19:01:27,799 [main] S2Containerを作成しました。path=sample2/sample.dicon
DoWorkImpl#doWork()だよ!
DoWorkImpl#doWork()だよ!
DoWorkImpl#doWork()だよ!
------------- finish -------------
|
DIするオブジェクトに対し、初期化方法を指定できます。
以下の方法があります。
・コンストラクタ・インジェクション
・セッター・インジェクション
・メソッド・インジェクション
・フィールド・インジェクション
おおざっぱに言うと、DIコンテナが戻り値として返すインスタンスを、初期化する際の、初期値指定方法です。
「instance属性」「autoBinding属性」については次で扱います(←これが重要)。
また「フィールド・インジェクション」については、別箇こちらで例を示します。
それぞれの使い方のサンプルコードを以下に示します。
EntryPoint.java |
package sample3;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* 「コンストラクタ・インジェクション」「セッター・インジェクション」「メソッド・インジェクション」のサンプル.
*/
public class EntryPoint {
public static void main(String[] args) {
String path = "sample3/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
// 受け取ったインスタンスを実行する
DoWork work1 = (DoWork)container.getComponent("doWork_ConstractorInjection");
work1.doWork();
DoWork work2 = (DoWork)container.getComponent("doWork_SetterInjection");
work2.doWork();
DoWork work3 = (DoWork)container.getComponent("doWork_MethodInjection");
work3.doWork();
System.out.println("------------- finish -------------");
}
}
|
DoWork.java |
package sample3;
public interface DoWork {
public void doWork();
}
|
DoWorkImpl.java |
package sample3;
import java.util.Date;
public class DoWorkImpl implements DoWork {
private String msg;
private Date date;
/** デフォルトコンストラクタ. */
public DoWorkImpl() {
}
/**
* 「コンストラクタインジェクション」を行う際、使用されるコンストラクタ.
*/
public DoWorkImpl(String msg, Date date) {
this.msg = msg;
this.date = date;
}
/** 「セッターインジェクション」を行う際、使用されるセッターメソッド. */
public void setMsg(String msg){ this.msg = msg; }
/** 「セッターインジェクション」を行う際、使用されるセッターメソッド. */
public void setDate(Date date){ this.date = date; }
/** 「メソッドインジェクション」 を行う際、使用されるメソッド. */
public void setup(String msg, Date date) {
System.out.println("setupが呼ばれました!");
this.msg = msg;
this.date = date;
}
public void doWork() {
System.out.println("DoWorkImpl#doWork()だよ!");
System.out.println("msg : "+msg);
System.out.println("date : "+date);
System.out.println();
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<!-- コンストラクタインジェクション -->
<component name="doWork_ConstractorInjection" class="sample3.DoWorkImpl">
<arg>"コンストラクタインジェクションですw"</arg>
<arg>new java.util.Date()</arg>
</component>
<!-- セッターインジェクション -->
<component name="doWork_SetterInjection" class="sample3.DoWorkImpl">
<property name="msg">"セッターインジェクションですw"</property>
<property name="date">new java.util.Date()</property>
</component>
<!-- メソッドインジェクション -->
<component name="doWork_MethodInjection" class="sample3.DoWorkImpl">
<initMethod name="setup">
<arg>"メソッドインジェクションですw"</arg>
<arg>new java.util.Date()</arg>
</initMethod>
</component>
</components>
|
■実行結果(コンソール出力) |
------------- start -------------
DEBUG 2012-02-19 19:38:58,193 [main] S2Containerを作成します。path=sample3/sample.dicon
DEBUG 2012-02-19 19:38:58,277 [main] S2Containerを作成しました。path=sample3/sample.dicon
setupが呼ばれました!
DoWorkImpl#doWork()だよ!
msg : コンストラクタインジェクションですw
date : Sun Feb 19 19:38:58 JST 2012
DoWorkImpl#doWork()だよ!
msg : セッターインジェクションですw
date : Sun Feb 19 19:38:58 JST 2012
DoWorkImpl#doWork()だよ!
msg : メソッドインジェクションですw
date : Sun Feb 19 19:38:58 JST 2012
------------- finish -------------
|
実行結果をみてみると、メソッドインジェクションがいきなり呼ばれていることがわかると思います。
今のdiconファイルの記述では、DIコンテナ内でインスタンスが最初に生成されている状態です。getComponentメソッドからの戻り値は、常に同じインスタンスとなります。これは設定でインスタンスの生成タイミングを変更可能です(指定方法は次で扱います)
「自動バインディング方法」と「インスタンス管理方法」の、2つテーマについてサンプルを書きます。
「自動バインディング方法」について
「コンストラクタ・インジェクション」と「セッター・インジェクション」に対して機能します。
自動バインディングはデフォルトで機能するようになっています。
機能のON・OFFなどはdiconファイル内のcomponentタグの属性値で設定します。
componentタグの属性 |
指定値 |
意味 |
備考 |
autoBinding |
auto |
「コンストラクター・インジェクション」「セッター・インジェクション」の両方で自動バインディングが機能する |
autoBinding属性を指定していない場合のデフォルト |
constructor |
「コンストラクター・インジェクション」のみで自動バインディングが機能する |
- |
property |
「セッター・インジェクション」のみで自動バインディングが機能する |
- |
none |
自動バインディングを行わない |
- |
また、「セッター・インジェクション」を使用する際、各々のpropertyタグに対して挙動を指定することも可能。
propertyタグの属性 |
指定値 |
意味 |
備考 |
bindingType |
must |
自動バインディングされない場合、例外を飛ばす |
- |
should |
自動バインディングされない場合、警告ログを出す |
bindingType属性を指定していない場合のデフォルト |
may |
自動バインディングされても、されなくても何もしない |
- |
none |
自動バインディングを行わない |
- |
上記のような設定が可能です。
■コンストラクタ・インジェクションを使用した例を以下に示します。
以下のプログラムでは、DIするクラス(DoWorkImpl)のコンストラクタに、diconファイルで設定した実装クラスのインターフェイスを引数にとっています。
このコンストラクタの引数に対し、Seasarが内部でマッチングを行い自動的にインスタンスを渡してくれます(このマッチング対象とするために、diconファイルにFortuneTellerImplとPrinterImplを記述しています)。
EntryPoint.java |
package sample4;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* 「自動バインディング方法」のコンストラクタ・インジェクションのサンプル.
*/
public class EntryPoint {
public static void main(String[] args) {
String path = "sample4/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
// 受け取ったインスタンスを実行する
DoWork work = (DoWork)container.getComponent("fortuneTelling");
work.doWork();
System.out.println("------------- finish -------------");
}
}
|
DoWork.java |
package sample4;
public interface DoWork {
public void doWork();
}
|
DoWorkImpl.java |
package sample4;
public class DoWorkImpl implements DoWork {
private FortuneTeller teller;
private Printer printer;
/** コンストラクタ・インジェクション用のコンストラクタ.*/
public DoWorkImpl(FortuneTeller teller, Printer printer) {
this.teller = teller;
this.printer = printer;
}
public void doWork() {
printer.print("今日の占い結果 : "+teller.doWork());
}
}
|
FortuneTeller.java |
package sample4;
public interface FortuneTeller {
public String doWork();
}
|
FortuneTellerImpl.java |
package sample4;
public class FortuneTellerImpl implements FortuneTeller {
public String doWork() {
return "ゆがみねぇな";
}
}
|
Printer.java |
package sample4;
public interface Printer {
public void print(String msg);
}
|
PrinterImpl.java |
package sample4;
public class PrinterImpl implements Printer {
public void print(String msg) {
System.out.println(msg);
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component name="fortuneTelling" class="sample4.DoWorkImpl"/>
<component class="sample4.FortuneTellerImpl"/>
<component class="sample4.PrinterImpl"/>
</components>
|
■実行結果(コンソール出力) |
------------- start -------------
DEBUG 2012-02-19 20:46:51,819 [main] S2Containerを作成します。path=sample4/sample.dicon
DEBUG 2012-02-19 20:46:51,882 [main] S2Containerを作成しました。path=sample4/sample.dicon
今日の占い結果 : ゆがみねぇな
------------- finish -------------
|
■続いて、セッター・インジェクションを使用した例を以下に示します
上で示した、コンストラクタ・インジェクションの例を少しいじっただけです^^;
EntryPoint.java |
package sample5;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* 「自動バインディング方法」のコンストラクタ・インジェクションのサンプル.
*/
public class EntryPoint {
public static void main(String[] args) {
String path = "sample5/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
// 受け取ったインスタンスを実行する
DoWork work = (DoWork)container.getComponent("fortuneTelling");
work.doWork();
System.out.println("------------- finish -------------");
}
}
|
DoWork.java |
package sample5;
public interface DoWork {
public void doWork();
}
|
DoWorkImpl.java |
package sample5;
public class DoWorkImpl implements DoWork {
private FortuneTeller teller;
private Printer printer;
/** デフォルトコンストラクタ.*/
public DoWorkImpl() {
}
/** セッター・インジェクション用メソッド. */
public void setTeller(FortuneTeller teller) { this.teller = teller; }
/** セッター・インジェクション用メソッド. */
public void setPrinter(Printer printer) { this.printer = printer; }
public void doWork() {
printer.print("今日の占い結果 : "+teller.doWork());
}
}
|
FortuneTeller.java |
package sample5;
public interface FortuneTeller {
public String doWork();
}
|
FortuneTellerImpl.java |
package sample5;
public class FortuneTellerImpl implements FortuneTeller {
public String doWork() {
return "ゆがみねぇな";
}
}
|
Printer.java |
package sample5;
public interface Printer {
public void print(String msg);
}
|
PrinterImpl.java |
package sample5;
public class PrinterImpl implements Printer {
public void print(String msg) {
System.out.println(msg);
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component name="fortuneTelling" class="sample5.DoWorkImpl">
<property name="printer" bindingType="must"/>
<property name="teller" bindingType="must"/>
</component>
<component class="sample5.FortuneTellerImpl"/>
<component class="sample5.PrinterImpl"/>
</components>
|
■実行結果(コンソール出力) |
------------- start -------------
DEBUG 2012-02-19 22:19:32,384 [main] S2Containerを作成します。path=sample5/sample.dicon
DEBUG 2012-02-19 22:19:32,454 [main] S2Containerを作成しました。path=sample5/sample.dicon
今日の占い結果 : ゆがみねぇな
------------- finish -------------
|
「インスタンス管理方法」について
getComponentするたびに、インスタンスを新規作成したものを返してほしかったりするケースがあります。デフォルト設定では同じインスタンスが何度も帰ってきます。
それを制御するのが「インスタンス管理方法」です。
diconファイルのcomponentタグのinstance属性で指定します。
component属性値 |
指定値 |
意味 |
備考 |
instance |
singleton |
S2Containerが内部でインスタンスを作成する。
常にその作成したインスタンスを返す(戻り値は同じインスタンスとなる)。 (参照1) |
デフォルトの設定値(未指定の場合こちらが選択される) |
prototype |
getComponentするたびに、S2Containerが新たなインスタンスを作成し、戻り値として返す。
戻り値は常に新しいインスタンスとなる。 |
- |
outer |
あらかじめ、S2Containerに対しインスタンスをプログラムの実装者がセットしておく必要がある(プログラム上から設定が可能)。
実装者がセットしたインスタンスがDIされる。 |
- |
request |
Webアプリケーションを作成する際に使用する。
S2ContainerFilterを使用する必要がある。 |
- |
session |
application |
(参照1) :
一度インスタンスを生成すると、内部でずっとそのインスタンスを持ちまわす・・・みたい。
アプリ終了時に、そのクラスの終了時にメソッドを実行させることができるらしい。diconファイルで以下のように指定すると、勝手に呼ばれる。
<component name="fortuneTelling" class="sample5.DoWorkImpl">
<destroyMethod name="syuuryouSyori">
<arg>"おわりだよんw"</arg>
</destroyMethod>
</component>
|
インスタンス管理方法については、instance属性の値を指定することで制御します。
これらの使い方の例示はここのページにいれると、このページが長くなるので、別途こちらに書いてます。
seasar2.4系で追加された機能。
フィールドにも値を設定するよってだけです。
publicなフィールドは、常にDI対象とみなされます。DI対象としたくない場合は、アクセス修飾子をpublicとしない、もしくは「@Binding(bindingType=BindingType.NONE)」と、@Bindingアノテーションを追加して、その属性でDI処理を行わないという指定を行う必要があります。
以下に例を示します。
EntryPoint.java |
package sample8;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* 「フィールド・インジェクション」のサンプル.
*/
public class EntryPoint {
public static void main(String[] args) {
String path = "sample8/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
SampleA sampleA1 = (SampleA)container.getComponent("sampleA");
sampleA1.proccess();
sleep();
SampleA sampleA2 = (SampleA)container.getComponent("sampleA");
sampleA2.proccess();
System.out.println("------------- finish -------------");
}
private static void sleep() {
try {
Thread.sleep(1000L);
} catch(Exception e) { e.printStackTrace(); }
}
}
|
DoWork.java |
package sample8;
public interface DoWork {
public void doWork();
}
|
DoWorkImpl.java |
package sample8;
import java.util.Date;
public class DoWorkImpl implements DoWork {
private String msg;
private Date date;
/**
* 「コンストラクタインジェクション」を行う際、使用されるコンストラクタ.
*/
public DoWorkImpl(String msg, Date date) {
this.msg = msg;
this.date = date;
}
public void doWork() {
System.out.println("DoWorkImpl#doWork()だよ!");
System.out.println("msg : "+msg);
System.out.println("date : "+date);
System.out.println();
}
}
|
SampleA.java |
package sample8;
import org.seasar.framework.container.annotation.tiger.Binding;
import org.seasar.framework.container.annotation.tiger.BindingType;
public class SampleA {
// privateフィールドにした場合
// @Binding(bindingType=BindingType.MUST)
// private DoWork doWork;
// publicフィールドにした場合
public DoWork doWork;
public void proccess() {
System.out.println("SampleA#proccess start ------------------");
doWork.doWork();
System.out.println("SampleA#proccess finish ------------------");
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component class="sample8.DoWorkImpl" instance="prototype">
<arg>"コンストラクタインジェクションですw"</arg>
<arg>new java.util.Date()</arg>
</component>
<component name="sampleA" class="sample8.SampleA" instance="prototype"/>
</components>
|
■実行結果 |
------------- start -------------
DEBUG 2012-03-10 23:04:44,621 [main] S2Containerを作成します。path=sample8/sample.dicon
DEBUG 2012-03-10 23:04:44,695 [main] S2Containerを作成しました。path=sample8/sample.dicon
SampleA#proccess start ------------------
DoWorkImpl#doWork()だよ!
msg : コンストラクタインジェクションですw
date : Sat Mar 10 23:04:44 JST 2012
SampleA#proccess finish ------------------
SampleA#proccess start ------------------
DoWorkImpl#doWork()だよ!
msg : コンストラクタインジェクションですw
date : Sat Mar 10 23:04:45 JST 2012
SampleA#proccess finish ------------------
------------- finish -------------
|
diconファイルは、1つにすべてを書いていると、ごちゃごちゃして見づらいので、分割してincludeする・・・ということが可能です。
・名前空間について
サンプルでは、以下のような形式のdiconファイルをよく使っていました。
componentsタグのnamespace属性が名前空間となります。
ファイル名と同じものを指定しています。違う名前を指定可能ですが、普通の運用ではファイル名と同じものを指定するかと思います。
sample.diconファイル |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component name="doWork" class="sample2.DoWorkImpl"/>
</components>
|
getComponentする際、名前を指定してコンポーネントを取得する際、上記sample.diconの場合、getComponentの引数に「"sample.doWork"」と記述することもできます。
登録するコンポーネントが増えてきた場合は、「ネームスペース.コンポーネントの名前」形式を使用した方が便利かとおもいます。
・includeの方法について
複数includeするには、複数includeタグを記述すればOKです。
includeタグはcomponentタグより前に記述しなければなりません。
当ファイルから、別の、XXXXX.diconファイルをincludeする場合、以下のように記述します。
includeの例 |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<include path = "XXXXX.dicon">
<component name="doWork" class="sample2.DoWorkImpl"/>
</components>
|
includeタグのpath属性には、読み込むdiconファイルのパスを指定します。ディレクトリの中にある場合はそのパスを記述する必要があります。パスを指定する際の区切り文字は「/」を使用します。
・includeを使った場合の、コンポーネント検索順序について
以下のような検索手順を行うみたいです。
(1) 自分のファイルの中を探す
(2) includeされたファイルを探す。includeタグが記述されている順にたどっていく。
なので、includeタグを記述する順番にも気を配った方が良いです。
「横断的関心事」というやつです。詳しくはググってください(ぉ
Seasar2が提供しているAOP機能の使い方をサンプルコードとともにあげています。
Seasar2のAOP機能(S2AOP)は、あらかじめ設定ファイル(diconファイル)を記述するだけで使用可能なインターセプターが提供されています。
また、インターセプターを独自に実装も可能です。
あらかじめ提供されているインターセプターについては、公式のリファレンスを見てください。
必要に迫られないと調べる気が起きない^^;
なので、ここでは、TraceInterceptor/ThrowsInterceptorしか扱いません。
インターセプターの設定方法は、基本的に、diconファイルに定義したcomponentタグの子要素としてaspectタグを追記します。
aspectタグのpointcut属性にて、インターセプター実行対象のメソッド名を記述します(この属性は省略可能。その場合、すべてのメソッドが対象になるらしい)。
メソッド名を直接指定するほか、正規表現による指定も可能です。
・・・まぁ、サンプルを見ればわかると思います。
また、ここでは「InterType」の説明を省略しています(単純に私が詳細を理解できていないため)。
名前からわかるように、処理のトレースに使用するインターセプターです。
TraceInterceptorの使い方の例を以下に示します。
EntryPoint.java |
package sample9;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* TraceInterceptorの使用例
*/
public class EntryPoint {
public static void main(String[] args) {
String path = "sample9/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
SampleA sampleA1 = (SampleA)container.getComponent("sampleA");
sampleA1.proccess();
System.out.println("------------- finish -------------");
}
}
|
SampleA.java |
package sample9;
public class SampleA {
public void proccess() {
System.out.println("+++++ SampleA#proccess start +++++");
System.out.println("SampleA#proccessが呼ばれたよ!");
System.out.println("+++++ SampleA#proccess finish +++++");
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component name="sampleA" class="sample9.SampleA" instance="prototype">
<aspect pointcut="proccess">
<component class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
</aspect>
</component>
</components>
|
■実行結果 |
------------- start -------------
DEBUG 2012-03-11 02:16:20,941 [main] S2Containerを作成します。path=sample9/sample.dicon
DEBUG 2012-03-11 02:16:21,006 [main] S2Containerを作成しました。path=sample9/sample.dicon
DEBUG 2012-03-11 02:16:21,068 [main] BEGIN sample9.SampleA#proccess()
+++++ SampleA#proccess start +++++
SampleA#proccessが呼ばれたよ!
+++++ SampleA#proccess finish +++++
DEBUG 2012-03-11 02:16:21,068 [main] END sample9.SampleA#proccess() : null
------------- finish -------------
|
例外が発生した場合に、共通のエラー処理を行うことを目的としたインターセプター。
※不明点
私が持ってるバージョン2.3の本に書いてあるサンプルでは、このThrowsInterceptorを使った場合、故意に例外を再throwしなければ、例外が発生しても、そのメソッドの処理を続行できる的なことが書いてある。
しかし、2.4系の環境で試してみたら、例外が発生した時点でそのメソッドは終了してインターセプター内の処理が終わったら、呼び出し元に処理が戻ってしまう。2.3系と2.4系の差異なのか、私がミスってるのか・・・調査中。
EntryPoint.java |
package sample10;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* ThrowsInterceptorの使用例
*/
public class EntryPoint {
public static void main(String[] args) throws Exception {
String path = "sample10/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
SampleA sampleA1 = (SampleA)container.getComponent("sampleA");
sampleA1.proccess();
System.out.println("------------- finish -------------");
}
}
|
SampleA.java |
package sample10;
public class SampleA {
public void proccess() throws Exception {
System.out.println("+++++ SampleA#proccess start +++++");
throw1();
System.out.println("SampleA#proccessが呼ばれたよ!");
System.out.println("+++++ SampleA#proccess finish +++++");
}
/** ぬるぽをわざと投げるクラス. */
public void throw1() throws Exception {
throw new NullPointerException("わざとだよwww");
}
}
|
OriginalThrowableInterceptor.java |
package sample10;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.ThrowsInterceptor;
/**
* ThrowsInterceptorの拡張.
*/
public class OriginalThrowableInterceptor extends ThrowsInterceptor {
/*
* 発生した例外クラス別に、handleThrowableの第一引数に例外クラスを指定することで
* 呼び出しを分けることが可能です。
*/
/** ぬるぽ用のハンドラ. */
public void handleThrowable(NullPointerException e, MethodInvocation invocation) throws Throwable {
System.out.println("++++++++++++++++++ OriginalThrowableInterceptor#handleThrowable start ++++++++++++++++++");
System.out.println("ぬるぽが来たとき用のハンドラだよ!");
System.out.println("++++++++++++++++++ OriginalThrowableInterceptor#handleThrowable finish ++++++++++++++++++");
}
/** ArithmeticException用のハンドラ */
public void handleThrowable(ArithmeticException e, MethodInvocation invocation) throws Throwable {
System.out.println("++++++++++++++++++ OriginalThrowableInterceptor#handleThrowable start ++++++++++++++++++");
System.out.println("計算のエラーが来たとき用のハンドラだよ!");
System.out.println("++++++++++++++++++ OriginalThrowableInterceptor#handleThrowable finish ++++++++++++++++++");
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component name="sampleA" class="sample10.SampleA" instance="prototype">
<aspect pointcut="proccess">
<component class="sample10.OriginalThrowableInterceptor"/>
</aspect>
</component>
</components>
|
■実行結果 |
------------- start -------------
DEBUG 2012-03-11 03:07:02,643 [main] S2Containerを作成します。path=sample10/sample.dicon
DEBUG 2012-03-11 03:07:02,708 [main] S2Containerを作成しました。path=sample10/sample.dicon
+++++ SampleA#proccess start +++++
++++++++++++++++++ OriginalThrowableInterceptor#handleThrowable start ++++++++++++++++++
ぬるぽが来たとき用のハンドラだよ!
++++++++++++++++++ OriginalThrowableInterceptor#handleThrowable finish ++++++++++++++++++
------------- finish -------------
|
以下に例を示します。
EntryPoint.java |
package sample11;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
/**
* 独自のインターセプターの作成方法について
*/
public class EntryPoint {
public static void main(String[] args) throws Exception {
String path = "sample11/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
SampleA sampleA1 = (SampleA)container.getComponent("sampleA");
sampleA1.proccess();
System.out.println("------------- finish -------------");
}
}
|
SampleA.java |
package sample11;
public class SampleA {
public void proccess() {
System.out.println("+++++ SampleA#proccess start +++++");
System.out.println("SampleA#proccessが呼ばれたよ!");
System.out.println("+++++ SampleA#proccess finish +++++");
}
}
|
OriginalInterceptor.java |
package sample11;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
public class OriginalInterceptor extends AbstractInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// 情報を表示する
showInfo(invocation);
// メソッドを実行する
Object ret = invocation.proceed();
System.out.println("メソッドの呼び出しが正常に終わったよ!");
return ret;
}
private void showInfo(MethodInvocation invocation) {
System.out.println("target class : "+getTargetClass(invocation).getName());
System.out.println("method name : "+invocation.getMethod().getName());
// その他、invocation.getArguments()でメソッドの引数を取得できたりする
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<component name="sampleA" class="sample11.SampleA" instance="prototype">
<aspect pointcut="proccess">
<component class="sample11.OriginalInterceptor"/>
</aspect>
</component>
</components>
|
■実行結果 |
------------- start -------------
DEBUG 2012-03-11 03:29:31,992 [main] S2Containerを作成します。path=sample11/sample.dicon
DEBUG 2012-03-11 03:29:32,055 [main] S2Containerを作成しました。path=sample11/sample.dicon
target class : sample11.SampleA
method name : proccess
+++++ SampleA#proccess start +++++
SampleA#proccessが呼ばれたよ!
+++++ SampleA#proccess finish +++++
メソッドの呼び出しが正常に終わったよ!
------------- finish -------------
|
diconファイルにいちいちコンポーネント登録を行っていくのは面倒です。
なので、指定したパッケージ以下のものすべてをコンポーネントとして登録・・・なんてことが可能です(除外設定や、正規表現にマッチするもののみ登録ということもできます)。
ここでは、DIするコンポーネントと、インターセプターの自動登録を以下に示します。
EntryPoint.java |
package sample12;
import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import sample12.di.Sample;
/**
* コンポーネントの自動登録について
*/
public class EntryPoint {
public static void main(String[] args) throws Exception {
String path = "sample12/sample.dicon";
System.out.println("------------- start -------------");
// S2Containerを初期化する
S2Container container = S2ContainerFactory.create(path);
container.init();
Sample sample = (Sample)container.getComponent(Sample.class);
sample.proccess();
System.out.println("------------- finish -------------");
}
}
|
Sample.java |
package sample12.di;
public interface Sample {
public void proccess();
}
|
SampleImpl.java |
package sample12.di;
public class SampleImpl implements Sample {
public void proccess() {
System.out.println("+++++ SampleImpl#proccess start +++++");
System.out.println("SampleImpl#proccessが呼ばれたよ!");
System.out.println("+++++ SampleImpl#proccess finish +++++");
}
}
|
DummySampleImpl.java |
package sample12.di;
public class DummySampleImpl implements Sample {
public void proccess() {
System.out.println("+++++ DummySampleImpl#proccess start +++++");
System.out.println("DummySampleImpl#proccessが呼ばれたよ!");
System.out.println("+++++ DummySampleImpl#proccess finish +++++");
}
}
|
OriginalInterceptor.java |
package sample12.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
public class OriginalInterceptor extends AbstractInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
// 情報を表示する
showInfo(invocation);
// メソッドを実行する
Object ret = invocation.proceed();
System.out.println("メソッドの呼び出しが正常に終わったよ!");
return ret;
}
private void showInfo(MethodInvocation invocation) {
System.out.println("target class : "+getTargetClass(invocation).getName());
System.out.println("method name : "+invocation.getMethod().getName());
// その他、invocation.getArguments()でメソッドの引数を取得できたりする
}
}
|
SampleOriginalInterceptor.java |
package sample12.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
public class SampleOriginalInterceptor extends AbstractInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("SampleOriginalInterceptorだよ!");
// メソッドを実行する
Object ret = invocation.proceed();
return ret;
}
}
|
sample.dicon |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"
"http://www.seasar.org/dtd/components24.dtd">
<components namespace="sample">
<!-- DIするコンポーネントの自動登録 -->
<component class="org.seasar.framework.container.autoregister.FileSystemComponentAutoRegister">
<initMethod name="addClassPattern">
<arg>"sample12.di"</arg> <!-- どのパッケージ配下のクラスを登録するか指定する -->
<arg>".*Impl"</arg> <!-- 正規表現を使い「〜Impl」というクラスを登録対象としている -->
</initMethod>
<initMethod name="addIgnoreClassPattern">
<arg>"sample12.di"</arg> <!-- どのパッケージ配下が対象か指定する -->
<arg>"Dummy.*Impl"</arg> <!-- 正規表現を使い「Dummy〜Impl」というクラスを登録対象外としている -->
</initMethod>
</component>
<!-- インターセプターの自動登録では、1つしかインターセプターを設定できないため
複数指定したい場合は、InterceptorChainを使う -->
<component name="original1" class="sample12.interceptor.OriginalInterceptor"/>
<component name="original2" class="sample12.interceptor.SampleOriginalInterceptor"/>
<component name="originalInterceptorChain" class="org.seasar.framework.aop.interceptors.InterceptorChain">
<initMethod name="add"><arg>original1</arg></initMethod>
<initMethod name="add"><arg>original2</arg></initMethod>
</component>
<!-- インターセプターの自動登録 -->
<component class="org.seasar.framework.container.autoregister.AspectAutoRegister">
<property name="interceptor">originalInterceptorChain</property>
<initMethod name="addClassPattern">
<arg>"sample12.di"</arg> <!-- どのパッケージ配下のクラスを設定するか指定する -->
<arg>".*Impl"</arg> <!-- 正規表現を使い「〜Impl」というクラスを登録対象としている -->
</initMethod>
<initMethod name="addIgnoreClassPattern">
<arg>"sample12.di"</arg> <!-- どのパッケージ配下が対象か指定する -->
<arg>"Dummy.*Impl"</arg> <!-- 正規表現を使い「Dummy〜Impl」というクラスを登録対象外としている -->
</initMethod>
</component>
</components>
|
■実行結果 |
------------- start -------------
DEBUG 2012-03-11 04:44:24,086 [main] S2Containerを作成します。path=sample12/sample.dicon
DEBUG 2012-03-11 04:44:24,174 [main] S2Containerを作成しました。path=sample12/sample.dicon
target class : sample12.di.SampleImpl
method name : proccess
SampleOriginalInterceptorだよ!
+++++ SampleImpl#proccess start +++++
SampleImpl#proccessが呼ばれたよ!
+++++ SampleImpl#proccess finish +++++
メソッドの呼び出しが正常に終わったよ!
------------- finish -------------
|
定義ファイルに設定をしなくても使えるコンポーネントがあるらしい。
一覧は公式のリファレンス参照。
これは覚えておいた方が良いと思ったので、わざわざ項目を設けた。