Seasar2でアノテーションを使って自動AOPその2

id:koichikさんよりinitMethodタグを使って初期化処理もS2に任せられるとのアドバイスを頂きました。ありがとうございます。
早速試していて気付いたのですが・・・当然の話ですが、Aspectを適用するコンポーネントの設定ファイルから、Interceptorのコンポーネントが見えてないと初期化に失敗してしまうんですね。自分はここら辺で詰まって、それで色々手動でComponentDefを初期化したりして、それがそのままになってしまっていました。
で、早速修正。

AnnotationAutoRegister

ComponentDefのdestory、init処理を削除

	@Override
	protected void regist(ComponentDef componentDef) {

		// 中略

		if (pointcut != null) {
			AspectDef aspectDef = new AspectDefImpl(pointcut);
			aspectDef.setExpression(interceptorName);
			componentDef.addAspectDef(aspectDef);
		}
	}

aop.dicon

Interceptorの設定を別ファイルに分けてincludeする。

<?xml version="1.0" encoding="Windows-31J"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
	"http://www.seasar.org/dtd/components21.dtd">
<components namespace="aop">
	<include path="test/common.dicon"/>
	
	<!-- 初期化 -->
	<component name="autoRegisterInit" class="test.AutoRegisterInit">
		<initMethod name="init"/>
	</component>
	
	<!-- トランザクション自動AOP -->
	<component name="annotationAllTransactionRegister" class="test.AnnotationAutoRegister">
		<property name="annotationClass">@test.Transaction@class</property>
		<property name="interceptorName">"common.annotationAllTransaction"</property>
	</component>
		
	<!-- Component -->
	<component class="test.Action1"/>
	<component class="test.Action2"/>
</components>

aop2.dicon

他のdiconファイルのコンポーネントにも自動アスペクトを定義できるよう、interceptorの定義を書いたdiconファイルをインクルード

<?xml version="1.0" encoding="Windows-31J"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
	"http://www.seasar.org/dtd/components21.dtd">
<components namespace="aop2">
	<include path="test/common.dicon"/>
		
	<!-- Component -->
	<component class="test.Action3"/>
	<component class="test.Action4"/>
</components>

common.dicon

Interceptorの定義を記述

<?xml version="1.0" encoding="Shift_JIS"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container//EN"
"http://www.seasar.org/dtd/components.dtd">
<components namespace="common">
	<include path="j2ee.dicon"/>
	
	<!-- アノテーション対応トランザクションインターセプター -->
	<component name="annotationAllTransaction" class="test.AnnotationTransactionInterceptor">
		<property name="interceptorMap">
			#{@test.TransactionType@Required : j2ee.requiredTx,
			@test.TransactionType@RequiresNew : j2ee.requiresNewTx,
			@test.TransactionType@Mandatory : j2ee.mandatoryTx,
			@test.TransactionType@NotSupported : j2ee.notSupportedTx}
		</property>
	</component>

</components>

app.dicon

クラスパスのルートに置くdiconファイル

<?xml version="1.0" encoding="Windows-31J"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN"
	"http://www.seasar.org/dtd/components21.dtd">
<components>
	<include path="test/aop.dicon"/>
	<include path="test/aop2.dicon"/>
</components>

Action3クラス

Action1クラスを継承

package test;

public class Action3 extends Action1 {

}

Action4クラス

package test;

public class Action4 {

	@Transaction	
	public void execute() {
		System.out.println("Action4.execute()");
	}

	public void execute(String param) {
		System.out.println("Action4:" + param);		
	}
	
	public void execute2() {
		System.out.println("Action4.execute2()");
	}
}

Transactionアノテーション

継承クラスにもアノテーションを有効にするように修正

package test;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Transaction {
	TransactionType value() default TransactionType.Required;
}

Mainクラス

Webで利用する時のことを意識して、初期化処理をSingletonS2ContainerFactoryにやってもらいました。

package test;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerFactory;
import org.seasar.framework.container.factory.SingletonS2ContainerFactory;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SingletonS2ContainerFactory.init();
		S2Container container = SingletonS2ContainerFactory.getContainer();
		
		Action1 action1 = (Action1) container.getComponent(Action1.class);
		Action2 action2 = (Action2) container.getComponent(Action2.class);
		Action3 action3 = (Action3) container.getComponent(Action3.class);
		Action4 action4 = (Action4) container.getComponent(Action4.class);
		
		action1.execute();
		action1.execute("Hello");
		action1.execute2();
		System.out.println();
		action2.execute();
		action2.execute("Hello");
		action2.execute2();
		System.out.println();
		action3.execute();
		action3.execute("Hello");
		action3.execute2();
		System.out.println();
		action4.execute();
		action4.execute("Hello");
		action4.execute2();
	}

}

実行結果

DEBUG 2005-09-03 07:48:35,281 [main] トランザクションを開始しました
Action1.execute()
DEBUG 2005-09-03 07:48:35,281 [main] トランザクションをコミットしました
DEBUG 2005-09-03 07:48:35,281 [main] トランザクションを開始しました
Action1:Hello
DEBUG 2005-09-03 07:48:35,281 [main] トランザクションをコミットしました
Action1.execute2()

Action2.execute()
DEBUG 2005-09-03 07:48:35,281 [main] トランザクションを開始しました
Action2:Hello
DEBUG 2005-09-03 07:48:35,281 [main] トランザクションをコミットしました
Action2.execute2()

DEBUG 2005-09-03 07:48:35,406 [main] トランザクションを開始しました
Action1.execute()
DEBUG 2005-09-03 07:48:35,406 [main] トランザクションをコミットしました
DEBUG 2005-09-03 07:48:35,406 [main] トランザクションを開始しました
Action1:Hello
DEBUG 2005-09-03 07:48:35,406 [main] トランザクションをコミットしました
Action1.execute2()

DEBUG 2005-09-03 07:48:35,406 [main] トランザクションを開始しました
Action4.execute()
DEBUG 2005-09-03 07:48:35,406 [main] トランザクションをコミットしました
Action4:Hello
Action4.execute2()

上手くいきました!
今までは初期化処理を強引に作ってしまっていたのですが、全てS2にお任せすることが出来ました。
それにしても、アノテーションを利用したAspectの設定は非常に便利ですね。一度作ると、例外処理だとか他にも色々なものを作りたくなってしまって、最近はそういうのばかり作ってます(笑)。個人の自作でも簡単にここまで出来るんだから、アノテーションに本格対応したDIコンテナが出れば、開発スタイルは一変しそうな気がします。