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コンテナが出れば、開発スタイルは一変しそうな気がします。