Spring AOP AspectJアノテーションの例

Spring AOP + AspectJアノテーションの例

このチュートリアルでは、AspectJアノテーションをSpring AOPフレームワークに統合する方法を示します。 簡単に言えば、Spring AOP + AspectJを使用すると、メソッドを簡単にインターセプトできます。

一般的なAspectJアノテーション:

  1. @Before –メソッド実行前に実行

  2. @After –メソッドが結果を返した後に実行

  3. @AfterReturning –メソッドが結果を返した後に実行し、返された結果もインターセプトします。

  4. @AfterThrowing –メソッドが例外をスローした後に実行

  5. @Around –メソッドの実行を実行し、上記の3つのアドバイスをすべて組み合わせます。

Note
AspectJをサポートしないSpringAOPの場合は、このbuild-in Spring AOP examplesをお読みください。

1. ディレクトリ構造

この例のディレクトリ構造を参照してください。

directory structure of this example

2. プロジェクトの依存関係

AspectJを有効にするには、aspectjrt.jaraspectjweaver.jar、およびspring-aop.jarが必要です。 次のMavenpom.xmlファイルを参照してください。

AspectJ supported since Spring 2.0
この例ではSpring 3を使用していますが、AspectJ機能はSpring2.0以降でサポートされています。

ファイル:pom.xml



    
        3.0.5.RELEASE
    

    

        
            org.springframework
            spring-core
            ${spring.version}
        

        
            org.springframework
            spring-context
            ${spring.version}
        

        
        
            org.springframework
            spring-aop
            ${spring.version}
        

        
            org.aspectj
            aspectjrt
            1.6.11
        

        
            org.aspectj
            aspectjweaver
            1.6.11
        

    

3. 春豆

メソッドがほとんどない通常のBeanは、後でAspectJアノテーションを介してインターセプトします。

package com.example.customer.bo;

public interface CustomerBo {

    void addCustomer();

    String addCustomerReturnValue();

    void addCustomerThrowException() throws Exception;

    void addCustomerAround(String name);
}
package com.example.customer.bo.impl;

import com.example.customer.bo.CustomerBo;

public class CustomerBoImpl implements CustomerBo {

    public void addCustomer(){
        System.out.println("addCustomer() is running ");
    }

    public String addCustomerReturnValue(){
        System.out.println("addCustomerReturnValue() is running ");
        return "abc";
    }

    public void addCustomerThrowException() throws Exception {
        System.out.println("addCustomerThrowException() is running ");
        throw new Exception("Generic Error");
    }

    public void addCustomerAround(String name){
        System.out.println("addCustomerAround() is running, args : " + name);
    }
}

4. AspectJを有効にする

Spring構成ファイルに「<aop:aspectj-autoproxy />」を入れて、アスペクト(インターセプター)と通常のBeanを定義します。

ファイル:Spring-Customer.xml



    

    

    
    

4. AspectJ @Before

以下の例では、logBefore()メソッドはcustomerBoインターフェースのaddCustomer()メソッドの実行前に実行されます。

Note
AspectJの「ポイントカット」は、インターセプトするメソッドを宣言するために使用されます。サポートされているポイントカット式の完全なリストについては、このSpring AOP pointcuts guideを参照してください。

ファイル:LoggingAspect.java

package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

    @Before("execution(* com.example.customer.bo.CustomerBo.addCustomer(..))")
    public void logBefore(JoinPoint joinPoint) {

        System.out.println("logBefore() is running!");
        System.out.println("hijacked : " + joinPoint.getSignature().getName());
        System.out.println("******");
    }

}

それを実行します

    CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
    customer.addCustomer();

出力

logBefore() is running!
hijacked : addCustomer
******
addCustomer() is running

5. AspectJ @After

以下の例では、logAfter()メソッドはcustomerBoインターフェースの実行後に実行されます。addCustomer()メソッド。

ファイル:LoggingAspect.java

package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;

@Aspect
public class LoggingAspect {

    @After("execution(* com.example.customer.bo.CustomerBo.addCustomer(..))")
    public void logAfter(JoinPoint joinPoint) {

        System.out.println("logAfter() is running!");
        System.out.println("hijacked : " + joinPoint.getSignature().getName());
        System.out.println("******");

    }

}

それを実行します

    CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
    customer.addCustomer();

出力

addCustomer() is running
logAfter() is running!
hijacked : addCustomer
******

6. AspectJ @AfterReturning

以下の例では、logAfterReturning()メソッドはcustomerBoインターフェースの実行後に実行されます。addCustomerReturnValue()メソッド。 さらに、「returning」属性を使用して戻り値をインターセプトできます。

戻り値をインターセプトするには、「returning」属性の値(結果)がメソッドパラメーター(結果)と同じである必要があります。

ファイル:LoggingAspect.java

package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;

@Aspect
public class LoggingAspect {

   @AfterReturning(
      pointcut = "execution(* com.example.customer.bo.CustomerBo.addCustomerReturnValue(..))",
      returning= "result")
   public void logAfterReturning(JoinPoint joinPoint, Object result) {

    System.out.println("logAfterReturning() is running!");
    System.out.println("hijacked : " + joinPoint.getSignature().getName());
    System.out.println("Method returned value is : " + result);
    System.out.println("******");

   }

}

それを実行します

    CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
    customer.addCustomerReturnValue();

出力

addCustomerReturnValue() is running
logAfterReturning() is running!
hijacked : addCustomerReturnValue
Method returned value is : abc
******

7. AspectJ @AfterReturning

以下の例では、customerBoインターフェースのaddCustomerThrowException()メソッドが例外をスローしている場合にlogAfterThrowing()メソッドが実行されます。

ファイル:LoggingAspect.java

package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class LoggingAspect {

   @AfterThrowing(
      pointcut = "execution(* com.example.customer.bo.CustomerBo.addCustomerThrowException(..))",
      throwing= "error")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {

    System.out.println("logAfterThrowing() is running!");
    System.out.println("hijacked : " + joinPoint.getSignature().getName());
    System.out.println("Exception : " + error);
    System.out.println("******");

    }
}

それを実行します

    CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
    customer.addCustomerThrowException();

出力

addCustomerThrowException() is running
logAfterThrowing() is running!
hijacked : addCustomerThrowException
Exception : java.lang.Exception: Generic Error
******
Exception in thread "main" java.lang.Exception: Generic Error
    //...

8. AspectJ @Around

以下の例では、logAround()メソッドはcustomerBoインターフェイスのaddCustomerAround()メソッドの前に実行され、インターセプターがいつ制御をに戻すかを制御するために「joinPoint.proceed();」を定義する必要があります。元のaddCustomerAround()メソッド。

ファイル:LoggingAspect.java

package com.example.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;

@Aspect
public class LoggingAspect {

   @Around("execution(* com.example.customer.bo.CustomerBo.addCustomerAround(..))")
   public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {

    System.out.println("logAround() is running!");
    System.out.println("hijacked method : " + joinPoint.getSignature().getName());
    System.out.println("hijacked arguments : " + Arrays.toString(joinPoint.getArgs()));

    System.out.println("Around before is running!");
    joinPoint.proceed(); //continue on the intercepted method
    System.out.println("Around after is running!");

    System.out.println("******");

   }

}

それを実行します

    CustomerBo customer = (CustomerBo) appContext.getBean("customerBo");
    customer.addCustomerAround("example");

出力

logAround() is running!
hijacked method : addCustomerAround
hijacked arguments : [example]
Around before is running!
addCustomerAround() is running, args : example
Around after is running!
******

結論

最もパワーの低いAsjectJアノテーションを適用することを常にお勧めします。 春のAspectJに関するかなり長い記事です。 詳細な説明と例については、以下の参照リンクをご覧ください。

Anti annotation or using JDK 1.4 ?
心配ありません。AspectJはXML構成もサポートしています。このSpring AOP + AspectJ XML exampleを読んでください。

ソースコードをダウンロード

ダウンロード–Spring3-AOP-AspectJ-Example.zip(8 KB)