Spring AOPの例 - アドバイス

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)