Spring AOPの例–アドバイス
Spring AOP + AspectJ
AspectJの使用はより柔軟で強力です。このチュートリアル–Using AspectJ annotation in Spring AOPを参照してください。
Spring AOP(Aspect-oriented programming)フレームワークは、横断的関心事をアスペクトでモジュール化するために使用されます。 簡単に言うと、メソッドの実行時にSpring AOPが実行中のメソッドを乗っ取り、メソッドの実行前後に機能を追加するなど、一部のプロセスを傍受するためのインターセプターに過ぎません。
Spring AOPでは、4種類のアドバイスがサポートされています:
-
アドバイスの前–メソッドの実行前に実行
-
アドバイスを返した後–メソッドが結果を返した後に実行します
-
アドバイスをスローした後–メソッドが例外をスローした後に実行します
-
Around advice –メソッドの実行を回避し、上記の3つのアドバイスをすべて組み合わせます。
次の例は、Spring AOPのアドバイスがどのように機能するかを示しています。
簡単な春の例
後でデモを行うために、いくつかの印刷方法を使用して簡単な顧客サービスクラスを作成します。
package com.example.customer.services;
public class CustomerService {
private String name;
private String url;
public void setName(String name) {
this.name = name;
}
public void setUrl(String url) {
this.url = url;
}
public void printName() {
System.out.println("Customer name : " + this.name);
}
public void printURL() {
System.out.println("Customer website : " + this.url);
}
public void printThrowException() {
throw new IllegalArgumentException();
}
}
ファイル:Spring-Customer.xml – Bean構成ファイル
それを実行します
package com.example.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.customer.services.CustomerService;
public class App {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "Spring-Customer.xml" });
CustomerService cust = (CustomerService) appContext.getBean("customerService");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
}
}
}
出力
************************* Customer name : Yong Mook Kim ************************* Customer website : http://www.example.com *************************
Beanを実行し、いくつかの文字列を出力する単純なSpringプロジェクト。
Spring AOPのアドバイス
次に、Spring AOPのアドバイスを上記のカスタマーサービスに添付します。
1. アドバイスの前に
メソッドの実行前に実行されます。 MethodBeforeAdviceインターフェイスを実装するクラスを作成します。
package com.example.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class HijackBeforeMethod implements MethodBeforeAdvice
{
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("HijackBeforeMethod : Before method hijacked!");
}
}
Bean構成ファイル(Spring-Customer.xml)で、HijackBeforeMethodクラスのBeanと、「customerServiceProxy」という名前の新しいプロキシオブジェクトを作成します。
-
「ターゲット」-どのBeanをハイジャックするかを定義します。
-
「interceptorNames」-このプロキシ/ターゲットオブジェクトに適用するクラス(アドバイス)を定義します。
hijackBeforeMethodBean
Note
Springプロキシを使用するには、CGLIB2ライブラリを追加する必要があります。 Maven pom.xmlファイルに以下を追加します。
cglib cglib 2.2.2
もう一度実行すると、元のcustomerService Beanではなく新しいcustomerServiceProxybeanが取得されます。
package com.example.common;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.customer.services.CustomerService;
public class App {
public static void main(String[] args) {
ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "Spring-Customer.xml" });
CustomerService cust =
(CustomerService) appContext.getBean("customerServiceProxy");
System.out.println("*************************");
cust.printName();
System.out.println("*************************");
cust.printURL();
System.out.println("*************************");
try {
cust.printThrowException();
} catch (Exception e) {
}
}
}
出力
************************* HijackBeforeMethod : Before method hijacked! Customer name : Yong Mook Kim ************************* HijackBeforeMethod : Before method hijacked! Customer website : http://www.example.com ************************* HijackBeforeMethod : Before method hijacked!
すべてのcustomerServiceのメソッドが実行される前に、HijackBeforeMethod’s before()メソッドが実行されます。
2. アドバイスを返した後
メソッドに結果が返された後に実行されます。 AfterReturningAdviceインターフェースを実装するクラスを作成します。
package com.example.aop;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class HijackAfterMethod implements AfterReturningAdvice
{
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("HijackAfterMethod : After method hijacked!");
}
}
Bean構成ファイル
hijackAfterMethodBean
もう一度実行して、出力
************************* Customer name : Yong Mook Kim HijackAfterMethod : After method hijacked! ************************* Customer website : http://www.example.com HijackAfterMethod : After method hijacked! *************************
返されるすべてのcustomerServiceのメソッドの結果の後に、HijackAfterMethod’s afterReturning()メソッドが実行されます。
3. アドバイスを投げた後
メソッドが例外をスローした後に実行されます。 ThrowsAdviceインターフェイスを実装するクラスを作成し、IllegalArgumentException例外を乗っ取るためのafterThrowingメソッドを作成します。
package com.example.aop;
import org.springframework.aop.ThrowsAdvice;
public class HijackThrowException implements ThrowsAdvice {
public void afterThrowing(IllegalArgumentException e) throws Throwable {
System.out.println("HijackThrowException : Throw exception hijacked!");
}
}
Bean構成ファイル
hijackThrowExceptionBean
もう一度実行して出力
************************* Customer name : Yong Mook Kim ************************* Customer website : http://www.example.com ************************* HijackThrowException : Throw exception hijacked!
customerServiceのメソッドが例外をスローした場合、HijackThrowException’s afterThrowing()メソッドを実行します。
4. 周りのアドバイス
上記の3つのアドバイスすべてを組み合わせて、メソッドの実行中に実行します。 MethodInterceptorインターフェースを実装するクラスを作成します。 元のメソッドの実行を続行するには、“methodInvocation.proceed();を呼び出す必要があります。そうしないと、元のメソッドは実行されません。
package com.example.aop;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class HijackAroundMethod implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Method name : "
+ methodInvocation.getMethod().getName());
System.out.println("Method arguments : "
+ Arrays.toString(methodInvocation.getArguments()));
// same with MethodBeforeAdvice
System.out.println("HijackAroundMethod : Before method hijacked!");
try {
// proceed to original method call
Object result = methodInvocation.proceed();
// same with AfterReturningAdvice
System.out.println("HijackAroundMethod : Before after hijacked!");
return result;
} catch (IllegalArgumentException e) {
// same with ThrowsAdvice
System.out.println("HijackAroundMethod : Throw exception hijacked!");
throw e;
}
}
}
Bean構成ファイル
hijackAroundMethodBean
もう一度実行して出力
************************* Method name : printName Method arguments : [] HijackAroundMethod : Before method hijacked! Customer name : Yong Mook Kim HijackAroundMethod : Before after hijacked! ************************* Method name : printURL Method arguments : [] HijackAroundMethod : Before method hijacked! Customer website : http://www.example.com HijackAroundMethod : Before after hijacked! ************************* Method name : printThrowException Method arguments : [] HijackAroundMethod : Before method hijacked! HijackAroundMethod : Throw exception hijacked!
すべてのcustomerServiceのメソッドが実行された後、HijackAroundMethod’s invoke()メソッドが実行されます。
結論
ほとんどのSpring開発者は、すべてのアドバイスタイプを適用できるため、「Around advice」を実装していますが、要件を満たすには最適なアドバイスタイプを選択する必要があります。
Pointcut
この例では、カスタマーサービスクラスのすべてのメソッドが自動的にインターセプト(アドバイス)されます。 ただし、ほとんどの場合、メソッド名を介してメソッドをインターセプトするには、Pointcut and Advisorを使用する必要があります。
ソースコードをダウンロード
ダウンロード–Spring-AOP-Advice-Examples.zip(8 KB)