Spring 3シリーズ9-Spring AOP——Advice

39655 ワード

Spring 3シリーズ9-Spring AOP——Advice
 
Spring AOPはAsppect-orented programmingであり、切断面向けプログラミングは対象向けプログラミングの補足として、処理システムにおいて各モジュール(異なる方法)に分布するクロス懸念点に特化した問題である.簡単に言えば、いくつかの処理過程をブロックするブロックです.例えば、methodが実行されると、Spring AOPは実行中のmethodをハイジャックし、methodが実行される前または後に追加の機能を追加することができます.
 
Spring AOPでは、4種類のお知らせ(Advice)をサポートします.
Before advice      ——method実行前のお知らせ
After returning advice-methodは結果を返してお知らせします.
After throwing advice–methodが異常を投げたらお知らせします.
Aound advice–サラウンド通知は、以上の3つのタイプを組み合わせています.
 
この例はSpring AOPの働きを説明します.
まず簡単にAOPを使わない例です.
まず簡単なServiceを作成し、後でデモンストレーションするために、このクラスに簡単な印刷methodをいくつか追加しました.
Custoomer Service.javaは以下の通りです.
package com.lei.demo.aop.advice;

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();
    }

}
 
XmlプロファイルAring-AOP-Advice.xmlは以下の通りです.
<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.lei.demo.aop.advice.CustomerService">
        <property name="name" value="LeiOOLei" />
        <property name="url" value="http://www.cnblogs.com/leiOOlei/" />
    </bean>
 
</beans>
 
 以下のコードを実行します.
package com.lei.demo.aop.advice;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        ApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] { "Spring-AOP-Advice.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:LeiOOLei
******************************************
Customer website:http://www.cnblogs.com/leiOOlei/
******************************************
 
1.      Before Advice
インターフェースMethodBefore Adviceを実現したclassを作成し、methodを実行する前に、下のコードを実行します.
HujackBefore Method.javaは以下の通りです.
package com.lei.demo.aop.advice;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class HijackBeforeMethod implements MethodBeforeAdvice {

    public void before(Method arg0, Object[] args, Object target)
            throws Throwable {
        System.out.println("HijackBeforeMethod : Before method hijacked!");
        
    }

}
 
 設定ファイルに新しいbeanを追加してHujackBeforeMethodを配置し、新しいプロキシを作成して、customerServiceProxyと名づけます.
「target」はどのbeanを乗っ取りたいかを定義します.
「interceptorNames」はあなたがどのクラスを使って乗っ取りたいかを定義します.
Appring-AOP-Advice.xmlは以下の通りです.
<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.lei.demo.aop.advice.CustomerService">
        <property name="name" value="LeiOOLei" />
        <property name="url" value="http://www.cnblogs.com/leiOOlei/" />
    </bean>
    
    <bean id="hijackBeforeMethodBean" class="com.lei.demo.aop.advice.HijackBeforeMethod" />
 
    <bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="customerService" />
        <property name="interceptorNames">
            <list>
                <value>hijackBeforeMethodBean</value>
            </list>
        </property>
    </bean>
 
</beans>
 
注意:
Spring proxyを使う前に、CGLOIB 2種類のライブラリを追加しなければなりません.以下はpom.xml依存です.
  <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
    </dependency>
 
下記のコードを実行します.代理に注意してください.
アプリ.javaは以下の通りです
package com.lei.demo.aop.advice;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

    public static void main(String[] args) {
        ApplicationContext appContext = new ClassPathXmlApplicationContext(
                new String[] { "Spring-AOP-Advice.xml" });
 
        CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxy");
 
        System.out.println("  Spring AOP   ");
        System.out.println("*************************");
        cust.printName();
        System.out.println("*************************");
        cust.printURL();
        System.out.println("*************************");
        
        try {
            cust.printThrowException();
        } catch (Exception e) {
 
        }
 
    }

}
 
出力結果:
Spring AOPを使うと以下の通りです.
******************************************
HijackBefore Method:Before method hijacked!
Customer name:LeiOOLei
******************************************
HijackBefore Method:Before method hijacked!
Customer website:http://www.cnblogs.com/leiOOlei/
******************************************
HijackBefore Method:Before method hijacked!
 
各customerServiceのmethodが実行される前に、HujackBeforeMethodのbefore方法を実行します.
 
2.      After Returning Advice
インターフェースAfterReturningAdviceを実現したclassを作成し、methodを実行した後、結果を返すまで下のコードを実行します.結果が返ってこないと、切り込みコードは実行されません.
HijackAfter Method.javaは以下の通りです.
package com.lei.demo.aop.advice;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class HijackAfterMethod implements AfterReturningAdvice {

    public void afterReturning(Object returnValue, Method method, Object[] args,
            Object target) throws Throwable {
        System.out.println("HijackAfterMethod : After method hijacked!");

    }

}
 
beanのプロファイルを修正して、hijackAfter MethodBenの構成を追加します.Aring-AOP-Advice.xmlは以下の通りです.
<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.lei.demo.aop.advice.CustomerService">
        <property name="name" value="LeiOOLei" />
        <property name="url" value="http://www.cnblogs.com/leiOOlei/" />
    </bean>
    
    <bean id="hijackBeforeMethodBean" class="com.lei.demo.aop.advice.HijackBeforeMethod" />
    <bean id="hijackAfterMethodBean" class="com.lei.demo.aop.advice.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>
 
App.javaを再実行したら、以下のように出力します.
Spring AOPを使うと以下の通りです.
******************************************
Customer name:LeiOOLei
HijackAfterMethod:After method hijacked!
******************************************
Customer website:http://www.cnblogs.com/leiOOlei/
HijackAfterMethod:After method hijacked!
******************************************
 
アウトプットの結果を見ることができます.各customerServiceのmethodは結果を実行した後、HujackAfterMethodのafterReturning方法を実行します.しかし、cust.print ThrowException()に実行した後、直接に異常を投げました.方法は正常に実行済みではないので、切り込みのafterReturning方法は実行しません.
 
3.      Afetr Throwing Advice
Throws Adviceインターフェースを実現したclassを作成し、IllagalArgement Exception異常をハイジャックし、ターゲットmethodを実行する時、IllagalArgement Exceptionを投げて、切り込みの方法を実行します.
HijackThrowException.javaは以下の通りです.
package com.lei.demo.aop.advice;

import org.springframework.aop.ThrowsAdvice;

import sun.awt.SunToolkit.IllegalThreadException;

public class HijackThrowException implements ThrowsAdvice {

    public void afterThrowing(IllegalArgumentException e) throws Throwable {
        System.out.println("HijackThrowException : Throw exception hijacked!");
    }

}
 
beanの設定ファイルを修正して、hijackThrowException Beanを加入しました.Aring-AOP-Advice.xmlは以下の通りです.
<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.lei.demo.aop.advice.CustomerService">
        <property name="name" value="LeiOOLei" />
        <property name="url" value="http://www.cnblogs.com/leiOOlei/" />
    </bean>
    
    <bean id="hijackBeforeMethodBean" class="com.lei.demo.aop.advice.HijackBeforeMethod" />
    <bean id="hijackAfterMethodBean" class="com.lei.demo.aop.advice.HijackAfterMethod" />
    <bean id="hijackThrowExceptionBean" class="com.lei.demo.aop.advice.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>
 
運転結果は以下の通りです
Spring AOPを使うと以下の通りです.
******************************************
Customer name:LeiOOLei
******************************************
Customer website:http://www.cnblogs.com/leiOOlei/
******************************************
HijackThrowException:Throw exception hijacked!
 
CustoomerServiceにおけるprint ThrowException方法を実行すると、Illegel Argement Exceptionをスローすると考えられていますが、HijackThrowExceptionによって獲得され、その中のafterThrowing方法が実行されます.なお、異常がIllgalAgMentExceptionでないとカットできない.
 
4.      Aound Advice
以上の3つの形のAdviceを組み合わせて、インターフェースMethodIntercepterを実現するclassを作成します.MethodInvocation.procedを通じて、元の方法を呼び出す必要があります.
HujackAound Method.javaは以下の通りです.
package com.lei.demo.aop.advice;

import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class HijackAroundMethod implements MethodInterceptor {

    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("Method name : "
                + methodInvocation.getMethod().getName());
        System.out.println("Method arguments : "
                + Arrays.toString(methodInvocation.getArguments()));
 
        //      MethodBeforeAdvice
        System.out.println("HijackAroundMethod : Before method hijacked!");
 
        try {
            //      ,   CustomerService    
            Object result = methodInvocation.proceed();
 
            //     AfterReturningAdvice
            System.out.println("HijackAroundMethod : After method hijacked!");
 
            return result;
 
        } catch (IllegalArgumentException e) {
            //     ThrowsAdvice
            System.out.println("HijackAroundMethod : Throw exception hijacked!");
            throw e;
        }
    }

}
 
beanのプロファイルを修正して、hijackAroudMethodBeanに加入しました.Aring-AOP-Advice.xmlは以下の通りです.
<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.lei.demo.aop.advice.CustomerService">
        <property name="name" value="LeiOOLei" />
        <property name="url" value="http://www.cnblogs.com/leiOOlei/" />
    </bean>
    
    <bean id="hijackBeforeMethodBean" class="com.lei.demo.aop.advice.HijackBeforeMethod" />
    <bean id="hijackAfterMethodBean" class="com.lei.demo.aop.advice.HijackAfterMethod" />
    <bean id="hijackThrowExceptionBean" class="com.lei.demo.aop.advice.HijackThrowException" />
    <bean id="hijackAroundMethodBean" class="com.lei.demo.aop.advice.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>
 
App.javaを実行し、出力結果:
Spring AOPを使うと以下の通りです.
******************************************
Method name:printName
Method argments:[]
HujackAound Method:Before method hijacked!
Customer name:LeiOOLei
HujackAound Method:After method hijacked!
******************************************
Method name:print URL
Method argments:[]
HujackAound Method:Before method hijacked!
Customer website:http://www.cnblogs.com/leiOOlei/
HujackAound Method:After method hijacked!
******************************************
Method name:print ThrowException
Method argments:[]
HujackAound Method:Before method hijacked!
HujackAound Method:Throw exception hijacked!
 
CusstomerServiceでは、各方法の呼び出しは、HujackAroudMethodのinvoke方法を実行しており、全体の切り込みポイントがターゲットのaroundを見ることができます.
 
Springのほとんどの開発者はAdviceだけを使用しています.すべてのタイプのAdviceを実現できるからです.実際のプロジェクト開発の中で、私達はやはりできるだけ適当なAdviceを選びます.
       以上の例では、CustoomerServiceのすべての方法は自動的にブロックされますが、ほとんどの場合、我々は一つのクラスのすべての方法をブロックする必要はなく、条件に合う方法をブロックする必要があります.この時、私たちはPointcut and Adviceを使う必要があります.つまり、切り込みポイントとお知らせです.これからは章の中で順次紹介します.