** SpringでAOP [#oa224132]

#setlinebreak(on);

#html(<table><tr><td style="border:1px solid #000000;">)
Spring Framework は、依存性の注入(Dependency Injection)やアスペクト指向プログラミング(AOP)を行う事が出来る
Javaプラットフォーム向けのオープンソースのフレームワークである。
#html(</td></tr></table>)

【 用語 】
|アスペクト指向プログラミング(AOP)|ソフトウェアの特定の振る舞いを「アスペクト」として分離して、モジュール化するプログラミング技法。&br;オブジェクト指向プログラミングの問題点を補うために考え出された手法。|
|ジョイントポイント|Aspectを織り込むことが可能なコード上の位置。&br;(メソッドやコンストラクタの実行前後など。)|
|ポイントカット|コード上にあるジョインポイントの集合から、処理を織り込むたい場所の絞り込みを行った部分集合を指す。|
|アドバイス|ポイントカットによって絞り込まれたジョインポイントに織り込む処理と&br;どのタイミングでその処理を行うかを記述したコードを指す。|
|インターセプター|処理の制御をインターセプト(横取り)する為の仕組み、プログラム等の事。|
|アドバイザ|アドバイスとポイントカットの両方を兼ね備えた、アスペクトをモジュール化したもの。|

&br;

【 設定ファイルの記述例A 】
 <?xml version="1.0" encoding="UTF-8"?> 
 <beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
 
 	<!-- 業務ロジックの定義 -->
 	<bean id="testService" class="example.spring.TestServiceImpl" />
 
 	<!-- アドバイスの定義 -->
 	<bean id="afterAdvice" class="example.spring.MyAfterAdvice" />
 	<bean id="beforeAdvice" class="example.spring.MyBeforeAdvice" />
 	<bean id="aroundAdvice" class="example.spring.MyAroundAdvice" />
 
 	<!-- アドバイザの定義 -->
 	<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
 		<property name="advice" ref="aroundAdvice" />  <!-- 適用するAdviceのbeanidを記述 ※複数NG -->
 		<property name="patterns" value=".*" />        <!-- メソッド名のパターンを記述 ※複数OK(カンマ区切り) -->
 	</bean>
 
 	<!-- AOPに関する情報を定義 -->
 	<bean id="beanNameAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">		
 		<property name="beanNames">
 			<value>testService</value>                 <!-- 対象クラスのbeanNameを記述 ※複数OK -->
 		</property>
 		<property name="interceptorNames">
 			<value>myAdvisor</value>                   <!-- 対象アドバイザのidを指定 ※複数OK -->
 		</property>
 	</bean>
 
 </beans>

&br;

- Advisorの設定例
 <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
 	<property name="advice" ref="AdviceのBean id"/>
 	<property name="pattern" value="正規表現などで記述された条件" />
 </bean>

&br;

- Advisorの種類
|クラス名|説明|h
|DefaultIntroductionAdvisor|クラスフィルタのみ定義したPointcutを持つ、Introduction Advice用のAdvisor。 Around Adviceなど他のAdviceには利用することができない|
|RegexpMethodPointcutAdvisor|正規表現を用いたPointcut(AbstractRegexpMethodPointcut)を内包するAdvisor。メソッドsetPatternから正規表現を指定できる|
|DynamicMethodMatcherPointcutAdvisor|パラメータの値などから、動的なPointcutを定義できるDynamicMethodMatcherPointcutを内包したAdvisor|
|StaticMethodMatcherPointcutAdvisor|クラスの型やメソッドのシグニチャのような静的な情報からPointcutを定義できるStaticMethodMatcherPointcutを内包したAdvisor|
|NameMatchMethodPointcutAdvisor|メソッド名からPointcutを定義するNameMatchMethodPointcutを内包したAdvisor|

&br;

【 設定ファイルの記述例B(AspectJスタイル) 】※aspectjweaver.jar が必要。
#html(<pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;<br />&lt;beans xmlns="http://www.springframework.org/schema/beans"<br />	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"<br />	xmlns:aop="http://www.springframework.org/schema/aop"<br />	xsi:schemaLocation="http://www.springframework.org/schema/beans<br />	http://www.springframework.org/schema/beans/spring-beans-2.0.xsd<br />	http://www.springframework.org/schema/aop<br />	http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"&gt;<br /><br />	&lt;!-- 業務ロジックの定義 --&gt;<br />	&lt;bean id="testService" class="net.magata.TestServiceImpl" /&gt;<br /><br />	&lt;!-- AOPに関する情報を定義 --&gt;<br />	&lt;aop:config&gt;<br />		&lt;aop:advisor pointcut="execution(* method(..))" advice-ref="simplelog" /&gt;<br />		&lt;aop:advisor pointcut="execution(* method(..))" advice-ref="beforeTrace" /&gt;<br />		&lt;aop:advisor pointcut="execution(* method(..))" advice-ref="beforeTrace" /&gt;<br />	&lt;/aop:config&gt;<br /><br />	&lt;!-- アドバイスの定義 --&gt;<br />	&lt;bean id="simplelog" class="org.springframework.aop.interceptor.SimpleTraceInterceptor"/&gt;<br />	&lt;bean id="beforeTrace" class="net.magata.MyBeforeAdvice"/&gt;<br />	&lt;bean id="afterTrace" class="net.magata.MyAfterAdvice"/&gt;<br /><br />&lt;/beans&gt;<br /></pre>)

&br;

- タグ要素
|タグ|説明|h
|<aop:config>|AOP設定の親となるタグ|
|<aop:aspect>〜</aop:aspect>|Aspectを作成するタグ。PointcutとAdviceをref属性によって利用するアドバイスを設定する|
|<aop:pointcut />|ポイントカット定義を行うタグ。|
|<aop:before>|メソッド実行前に処理されるアドバイスを定義する。|
|<aop:after>|メソッド実行後に処理されるアドバイスを定義する。|
|<aop:around>|メソッド実行前後に処理を加えることのできるアドバイスを定義する。|
|<aop:after-returning>|メソッドから特定の戻り値が返却された際に処理されるアドバイスを定義する。|
|<aop:after-throwing>|メソッドからExceptionがThrowされた際に処理されるアドバイスを定義する。|

&br;

- ポイントカット記述(AspectJスタイル)
|書式|説明|h
|excution|呼出先のメソッド、コンストラクタを指定する。|
|~|execution(メソッドの修飾子 メソッドの戻り値の型 パッケージ.インターフェイスまたはクラス名.メソッド名(引数の型[,…]) throws 例外)|
|within|呼出元のクラスを指定する。対象は指定されたクラスに宣言されたメソッドに限定される。(親クラスのメソッドは対象外)|
|target|呼出先の「クラス」を指定する|
|args|呼出先「メソッド」の引数の型を指定する|
|this|呼出元の「クラス」を指定する。親クラスのメソッドも対象になる。|

&br;

- executionで使用できるワイルドカード
|ワイルドカード|説明|h
|*|任意の型、またはクラス名、パッケージ名の一部の代わりとして使用できる|
|..|任意の引数と一致、または任意のクラス名、パッケージ名の一部として使用できる|
|+|クラス名、インターフェース名右側に記述すると、そのサブクラスまたはインタフェースの実装すべてが指定される|

&br;

【 各クラスの定義例 】
 // 自作のアドバイス(Before)
 package net.magata;
 import java.lang.reflect.Method;
 import org.springframework.aop.MethodBeforeAdvice;
 
 public class MyBeforeAdvice implements MethodBeforeAdvice {
 
 	// メソッド呼び出し前にログを出力する
 	public void before(Method method, Object[] args, Object target) throws Throwable {
 		System.out.println("Beforeアドバイスからのログ出力です");
 	}
 }

 // 自作のアドバイス(After)
 package net.magata;
 
 import java.lang.reflect.Method;
 import org.springframework.aop.AfterReturningAdvice;
 
 public class MyAfterAdvice implements AfterReturningAdvice {
 
 	// メソッド呼び出し後にログを出力する
 	public void afterReturning(Object ret, Method method, Object[] args, Object target) throws Throwable {
 
 		System.out.println("Afterアドバイスからのログ出力です");
 		if (target != null){
 			System.out.println(" 実行クラス:" + target.getClass().getName());
 		}
 		if (method != null){
 			System.out.println(" 実行メソッド:" + method.getName());
 		}
 		if (args != null){
 			for (int i = 0; i < args.length; i++) {
 				Object arg = args[i];
 				System.out.println(" 引数" + (i + 1) + ":" + arg.toString());
 			}
 		}
 		if (ret != null){
 			System.out.println(" 戻り値:" + ret.getClass().getName());
 		}
 	}
 }

&br;

 /*
   自作のアドバイス(Around) ※before + After + Throws
   ( org.aopalliance.intercept.MethodInterceptorなどの invokeメソッドを実装しても可 )
 */
 package net.magata;
 
 import java.lang.reflect.Method;
 
 import org.springframework.aop.AfterReturningAdvice;
 import org.springframework.aop.MethodBeforeAdvice;
 import org.springframework.aop.ThrowsAdvice;
 
 public class MyAroundAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
 
 	// メソッド呼び出し前にメッセージを出力する
 	public void before(Method method, Object[] args, Object target) throws Throwable {
 		
 		System.out.print("Beforeアドバイスからのログ出力です");
 		if ((args != null)&&(args.length > 0)) {
 			String argStr = (String)args[0];
 			System.out.print("   引数:" + argStr);
 		}
 		System.out.println("");
 	}
 
 	// メソッド呼び出し後にメッセージを出力する
 	public void afterReturning(Object ret, Method method, Object[] args, Object target) throws Throwable {
 		
 		System.out.println("Afterアドバイスからのログ出力です");
 		if (target != null){
 			System.out.println(" 実行クラス:" + target.getClass().getName());
 		}
 		if (method != null){
 			System.out.println(" 実行メソッド:" + method.getName());
 		}
 		if (args != null){
 			for (int i = 0; i < args.length; i++) {
 				Object arg = args[i];
 				System.out.println(" 引数" + (i + 1) + ":" + arg.toString());
 			}
 		}
 		if (ret != null){
 			System.out.println(" 戻り値:" + ret.getClass().getName());
 		}
 	}
 
 	// 例外発生時にメッセージを出力する
 	public void afterThrowing(Method m, Object[] args, Object target, Throwable ex){
 		System.out.println("Exception in method: " + m.getName() + " Exception is: "+ex.getMessage());
 	}
 
 }

&br;

 // 業務ロジック
 package net.magata;
 
 public class TestServiceImpl implements TestService {
 
 	public void methodA(){
 		System.out.println("methodAを実行(引数なし、戻り値なし)");
 	}
 	
 	public void methodB(String arg){
 		System.out.println("methodBを実行(引数:" + arg + "、戻り値なし)");
 	}
 	
 	public String methodC(String arg){
 		String ret = "こんにちわ";
 		System.out.println("methodCを実行(引数:" + arg + "、戻り値:" + ret +")");
 		return ret;
 	}
 }

&br;

 // 実行クラス
 package net.magata;
 
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 public class TestMain {
 	public static void main(String[] args) {
 
 		// アプリケーションコンテキストの取得
 		ApplicationContext context = new ClassPathXmlApplicationContext("net/magata/applicationContext.xml");
 
 		// 業務ロジッククラスのインスタンスを取得
 		TestService logic = (TestService)context.getBean("testService");
 
 		// 業務ロジックA(引数なし)の実行
 		logic.methodA();
 
 		// 業務ロジックB(引数あり)の実行
 		logic.methodB("Test!!");
 
 		// 業務ロジックC(引数あり、戻り値あり)の実行
 		String res = logic.methodC("Test!!");
 
 	}
 }

&br;


【 実行結果(Around適用時) 】
 Beforeアドバイスからのログ出力です
 methodAを実行(引数なし、戻り値なし)
 Afterアドバイスからのログ出力です
  実行クラス:example.spring.TestServiceImpl
  実行メソッド: methodA
 Beforeアドバイスからのログ出力です   引数:Test!!
 methodBを実行(引数:Test!!、戻り値なし)
 Afterアドバイスからのログ出力です
  実行クラス:example.spring.TestServiceImpl
  実行メソッド: methodB
  引数1:Test!!
 Beforeアドバイスからのログ出力です   引数:Test!!
 methodCを実行(引数:Test!!、戻り値:こんにちわ)
 Afterアドバイスからのログ出力です
  実行クラス:example.spring.TestServiceImpl
  実行メソッド: methodC
  引数1:Test!!
  戻り値:java.lang.String


トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS