Spring AOPの例 – アドバイス
Spring AOP(
アスペクト指向プログラミング
)フレームワークは、側面でのクロスカッティングの問題をモジュール化するために使用されます。シンプルにすると、メソッドが実行されるとき、Spring AOPが実行中のメソッドをハイジャックすることができ、メソッドの実行の前後に余分な機能を追加するなど、いくつかのプロセスをインターセプトするインターセプタだけです。
Spring AOPでは、4種類のアドバイスがサポートされています:
-
アドバイス前 – メソッド実行前に実行
-
アドバイスを返した後 – メソッドが結果を返した後に実行
-
アドバイスをスローした後 – メソッドが例外をスローした後に実行
-
周囲のアドバイス – メソッドの実行を中心に実行し、3つすべてを組み合わせる
上記のアドバイス。
次の例は、Spring AOPのアドバイスの仕組みを示しています。
簡単なSpringの例
後でデモンストレーションするための印刷方法が少ないシンプルな顧客サービスクラスを作成します。
package com.mkyong.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構成ファイル
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="customerService" class="com.mkyong.customer.services.CustomerService"> <property name="name" value="Yong Mook Kim"/> <property name="url" value="/"/> </bean> </beans>
それを実行します
package com.mkyong.common; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mkyong.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) { } } }
出力
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 顧客名:キムヨンムック ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 顧客のウェブサイト:/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
A simple Spring project to DI a bean and output some Strings.
Spring AOP Advices
Now, attach Spring AOP advices to above customer service.
1. Before advice
It will execute before the method execution. Create a class which
implements MethodBeforeAdvice interface.
パッケージcom.mkyong.aop; import java.lang.reflect.Method;インポートorg.springframework.aop.MethodBeforeAdvice; パブリッククラスHijackBeforeMethodはMethodBeforeAdviceを実装しています { @オーバーライド public void before(メソッドメソッド、Object[]args、Object target) Throwableをスローする{ System.out.println( "HijackBeforeMethod:メソッドがハイジャックされる前に!"); } }
Bean設定ファイル(Spring-Customer.xml)で、
HijackBeforeMethod
クラス、および新しいプロキシオブジェクト
‘
customerServiceProxy
‘。
-
‘target’ – ハイジャックするBeanを定義します。
-
‘interceptorNames’ – 適用したいクラス(アドバイス)を定義する
このプロキシ/ターゲットオブジェクト
<beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www .springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd "> <bean id = "customerService" class = "com.mkyong.customer.services.CustomerService"> <property name = "name" value = "Yong Mook Kim"/> <property name = "url" value = "/"/> </bean> <bean id = "hijackBeforeMethodBean" class = "com.mkyong.aop.HijackBeforeMethod"/> <bean id = "customerServiceProxy" class = "org.springframework.aop.framework.ProxyFactoryBean"> <property name = "target" red = "customer service"/> <property name = "interceptorNames"> <list> <value> hijackBeforeMethodBean </value> </list> </property> </bean> </beans>
-
注**
Springプロキシを使用するには、CGLIB2ライブラリを追加する必要があります。以下をMavenに追加する
pom.xmlファイル。
<依存関係> <groupId> cglib </groupId> <artifactId> cglib </artifactId> <version> 2.2.2 </version> </dependency>
もう一度実行すると、代わりに新しい
customerServiceProxy
beanが取得されます
元々のお客様のサービス**
パッケージcom.mkyong.common; インポートorg.springframework.context.ApplicationContext;インポートorg.springframework.context.support.ClassPathXmlApplicationContext; import com.mkyong.customer.services.CustomerService; パブリッククラス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(例外e){ } } }
出力
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** HijackBeforeMethod : Before method hijacked! Customer name : Yong Mook Kim ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** HijackBeforeMethod:メソッドがハイジャックされる前に! 顧客のウェブサイト:/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** HijackBeforeMethod:メソッドがハイジャックされる前に!
すべてのcustomerServiceのメソッドが実行される前に
HijackBeforeMethodのbefore()
メソッドが実行されます。
2.アドバイスを返した後
メソッドが結果を返した後に実行されます。
AfterReturningAdvice
インターフェイスを実装するクラスを作成します。
package com.mkyong.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設定ファイル
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="customerService" class="com.mkyong.customer.services.CustomerService"> <property name="name" value="Yong Mook Kim"/> <property name="url" value="/"/> </bean> <bean id="hijackAfterMethodBean" class="com.mkyong.aop.HijackAfterMethod"/> <bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="customerService"/> <property name="interceptorNames"> <list> <value>hijackAfterMethodBean</value> </list> </property> </bean> </beans>
もう一度実行すると、出力
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 顧客名:Yong Mook Kim HijackAfterメソッド:メソッドがハイジャックされた後! ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** Customer website :/HijackAfterMethod : After method hijacked! ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **
It will run the
HijackAfterMethod’s afterReturning()
method, after
every customerService’s methods that are returned result.
3. After throwing advice
It will execute after the method throws an exception. Create a class
which implements ThrowsAdvice interface, and create a
afterThrowing
method to hijack the
IllegalArgumentException
exception.
パッケージcom.mkyong.aop; org.springframework.aop.ThrowsAdviceをインポートします。 パブリッククラスHijackThrowExceptionは、ThrowsAdvice { public void afterThrowing(IllegalArgumentException e)throws Throwable { System.out.println( "HijackThrowException:例外をハイジャックしました!"); } }
Bean設定ファイル
<beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www .springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd "> <bean id = "customerService" class = "com.mkyong.customer.services.CustomerService"> <property name = "name" value = "Yong Mook Kim"/> <property name = "url" value = "/"/> </bean> <bean id = "hijackThrowExceptionBean" class = "com.mkyong.aop.HijackThrowException"/> <bean id = "customerServiceProxy" class = "org.springframework.aop.framework.ProxyFactoryBean"> <property name = "target" ref = "customerService"/> <property name = "interceptorNames"> <list> <value> hijackThrowExceptionBean </value> </list> </property> </bean> </beans>
再度実行し、出力する
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** Customer name : Yong Mook Kim ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** 顧客のウェブサイト:/** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** HijackThrowException:例外をハイジャックしました!
-
HijackThrowExceptionのafterThrowing()** メソッドを実行します。これは、customerServiceのメソッドが例外をスローした場合です。
4.周囲のアドバイス
上記の3つのアドバイスをすべて組み合わせ、メソッドの実行中に実行します。
MethodInterceptor
インタフェースを実装するクラスを作成します。元のメソッドの実行を続行するには、
“methodInvocation.proceed();
“を呼び出す必要があります。そうしないと、元のメソッドは実行されません。
package com.mkyong.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設定ファイル
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="customerService" class="com.mkyong.customer.services.CustomerService"> <property name="name" value="Yong Mook Kim"/> <property name="url" value="/"/> </bean> <bean id="hijackAroundMethodBean" class="com.mkyong.aop.HijackAroundMethod"/> <bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="customerService"/> <property name="interceptorNames"> <list> <value>hijackAroundMethodBean</value> </list> </property> </bean> </beans>
再度実行し、出力する
** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** メソッド名:printNameメソッドの引数:[]HijackAroundMethod:メソッドがハイジャックされる前に! 顧客名:Yong Mook Kim Hijack周辺方法:ハイジャックされた後! ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** Method name : printURL Method arguments :[]HijackAroundMethod : Before method hijacked! Customer website :/HijackAroundMethod : Before after hijacked! ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** メソッド名:printThrowExceptionメソッド引数:[]HijackAroundMethod:メソッドがハイジャックされる前に! HijackAroundMethod:例外をハイジャックしました!
It will run the
HijackAroundMethod’s invoke()
method, after every
customerService’s method execution.
Conclusion
Most of the Spring developers are just implements the ‘Around advice ‘,
since it can apply all the advice type, but a better practice should
choose the most suitable advice type to satisfy the requirements.
-
Pointcut**
In this example, all the methods in a customer service class are
intercepted (advice) automatically. But for most cases, you may need to
use
Pointcut and
Advisor
to intercept a method via it’s method name.