SpringでAOP †
【 用語 】
【 設定ファイルの記述例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>
【 設定ファイルの記述例B(AspectJスタイル) 】※aspectjweaver.jar が必要。 <?xml version="1.0" encoding="UTF-8"?>
【 各クラスの定義例 】 // 自作のアドバイス(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());
}
}
}
/*
自作のアドバイス(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());
}
}
// 業務ロジック
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;
}
}
// 実行クラス
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!!");
}
}
【 実行結果(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 |