Spring AOP
AOPの簡易理解は「元のソースコードに変更を加えずに新たな処理を追加する(挟み込む)こと」でよいか。
ここではSpring2.0以降のことを書いている(つもり)。
言葉の定義
- Aspect
- 横断的な関心事が持つ振る舞い(処理のこと)と、いつ振る舞いを適用するかをまとめたもの。
- 以下に記述するAdviceとPointcutをまとめたものをAspectという。
- Joinpoint
- Pointcut
- コード上にあるJoinpointの集合から、処理を織り込むたい場所の絞り込みを行った部分集合。
- 「add」ではじまるメソッドが実行された時だけだとすると、条件を「add*」のように絞り込む。
- Advice
- Joinpointで実行される処理。
- Intercepter
- 処理の制御をインターセプト(横取り)する為の仕組み、プログラム等の事。
- Advisor
- AdviceとPointcutの両方を兼ね備えた、アスペクトをモジュール化したもの。
以降、「Aspect」、「Pointcut」、「Advice」のbean定義ベースの設定例、最後にアノテーションの利用について書く。
Aspect
bean定義例
<aop:config> <aop:aspect id="aspect" ref="adviceClass"> ... </aop:aspect> </aop:config> <!-- Adviceを実装したクラスを定義。2行目にて参照。 --> <bean id="adviceClass" class="jp.example.aop.advice.AdviceImpl"> ... </bean>
Pointcut
bean定義例
<aop:config> <aop:pointcut id="pointcut1" expression="execution(* com.xyz.myapp.service.*.*(..))"/> <aop:pointcut id="pointcut2" expression="com.xyz.myapp.SystemArchitecture.businessService()"/> </aop:config>
expressionにはPointcutのパターン(Primitiveポイントカット)を記述する。
Primitiveポイントカット
- execution
- within
- 呼び出し元の「クラス」を指定。指定されたクラスから呼び出される。
- this
- 呼び出し元の「クラス」を指定。指定されたクラスから呼び出される。
- withinとは、親クラスで定義されたメソッドの呼び出しも対象となる点が異なる。
- target
- 呼び出し先のクラスを指定。ただし、staticフィールドは対象外。
- args
- 呼び出し先の「メソッド」の引数の型を指定。
Primitiveポイントカットは論理演算子「and」「or」「not」を使用することができる。
【例】expression="execution(* com.xyz.myapp.service.*.*(..)) or execution(* com.abc.myapp.service.*.*(..))"
Advice
種類
- Before Advice
- Joinpointの前に実行するAdvice。
- After Advice
- Joinpointの後に実行するAdvice。
- Around Advice
- Joinpointの前後で実行されるAdvice。
- Before AdviceプラスAfter Advice
- After Returning Advice
- Joinpointが完全に正常終了した後に実行されるAdvice。
- Advice対象メソッドの戻り値を受けて処理を行う。
- After Throwing Advice
- Joinpointで例外が発生した場合に実行されるAdvice。
- Advice対象メソッドスローした例外を受けて処理を行う。
bean定義例
<aop:config> <aop:aspect id="aspect" ref="adviceClass"> <aop:pointcut id="pointcut1" expression="execution(* getMessage())" /> <!-- 【Before Advice】pointcut-refにて上記Pointcut定義の参照、methodにて"adviceClass"で定義したクラスのどのメソッドの処理を挟み込むか指定 --> <aop:before pointcut-ref="pointcut1" method="beforeMethod" /> <!-- 【After Advice】Pointcutをpointcut-refで参照せずに直定義することもできる --> <aop:after pointcut=" execution(* jp.co.xyz.app1.service.*.*(..))" method="afterMethod" /> <!-- 【Around Advice】 --> <aop:around pointcut-ref="pointcut1" method="aroundMethod" /> <!-- 【After Returning Advice】returningにはAdvice対象メソッドの戻り値を代入するAdvice実装メソッドの引数名を指定 --> <aop:after-returning pointcut-ref="pointcut1" method="afterReturningMethod" returning="returnedValue" /> <!-- 【After Throwing Advice】throwingにはAdvice対象メソッドスローする例外を代入するAdvice実装メソッドの引数名を指定 --> <aop:after-throwing pointcut-ref="pointcut1" method="afterThrowingMethod" throwing="thrownException" /> </aop:aspect> </aop:config> <!-- Adviceを実装したクラスのbean定義 2行目にて使用 --> <bean id="adviceClass" class="jp.example.aop.advice.AdviceImpl" />
Advice実装例(jp.example.aop.advice.AdviceImpl)
package jp.example.aop.advice; import org.aspectj.lang.ProceedingJoinPoint; public class AdviceImpl { public void afterMethod() { System.out.println("afterMethod called."); } public void beforeMethod() { System.out.println("beforeMethod called."); } public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("aroundMethod called."); System.out.println("before proceed."); // Advice対象のメソッドが実行される。 pjp.proceed(); System.out.println("after proceed."); } /** * @param returnedValue Advice対象メソッドの返り値。 * String型になっているが、Advice対象メソッドの返り値の型に合わせる。 */ public void afterReturningMethod(String returnedValue) { System.out.println("afterReturningMethod called."); System.out.println("returnedValue is" + returnedValue + "."); } /** * @param thrownException Advice対象メソッドがスローする例外。 */ public void afterThrowingMethod(Exception thrownException) { System.out.println("afterThrowingMethod called."); System.out.println("thrownException is" + thrownException + "."); } }
アノテーションを利用したAOP
- @Aspect
- Adviceとなるクラスを指定するアノテーション
- @Before
- Before Adviceとなるメソッドを指定するアノテーション
- @After
- After Adviceとなるメソッドを指定するアノテーション
- @AfterReturning
- After Returning Adviceとなるメソッドを指定するアノテーション
- @Around
- Around Adviceとなるメソッドを指定するアノテーション
- @AfterThrowing
- After Throwing Adviceとなるメソッドを指定するアノテーション
★これらのアノテーションを使用する場合はbean定義ファイルに「
利用例
@Aspect public class AspectMessage { @After("execution(* exMethod())") public void hoge() { // メソッド終了後に動くAdvice System.out.println("after called."); } }
Advisor
bean定義例
<aop:config> <aop:advisor pointcut="* exec(..)" advice-ref="adviceImpl" /> </aop:config> <bean id="adviceImpl" class="jp.example.aop.advice.impl.AdviceImpl" />
また、トランザクション管理などSpringの既存機能を利用する場合は
- Around Advice
- org.aopalliance.intercept.MethodInterceptor
- Before Advice
- org.springframework.aop.MethodBeforeAdvice
- After Returning Advice
- org.springframework.aop.ThrowsAdvice
- After Throwing Advice
- org.springframework.aop.AfterReturningAdvice
参考
http://www.asahi-net.or.jp/~gq4r-msm/html/essay09/html/toUseSpringAop.html
http://static.springsource.org/spring/docs/2.5.x/reference/index.html