Spring AOPについての個人的な備忘録です。
参考
Spring 徹底入門
【Spring】Spring AOPについて
Spring AOP
JoinPoint(指定したメソッドの実行前や実行後などのタイミング)に対して、@Aspectアノテーションを付与したクラスで実装した処理を差し込めます。
使用可能なAdviceのアノテーション
| アノテーション | 説明 | 
|---|---|
| @Before | 対象のメソッドの実行前に処理が差し込まれる。 | 
| @AfterReturning | 対象のメソッドが正常終了した後に処理が差し込まれる。正常終了時のメソッドの戻り値を取得することもできる。 | 
| @AfterThrowing | 対象のメソッドが異常終了(例外がスローされたとき)に処理が差し込まれる。異常終了時の例外を取得することもできる。 | 
| @After | 対象のメソッドが正常終了や例外のスローに関わらず、終了時に処理が差し込まれる。 | 
| @Around | 最も強いAdvice。対象のメソッドの前後に処理が差し込まれる。 | 
実装
Before
SampleAspect.java
package com.example.demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SampleAspect {
    @Before("execution(public * com.example.demo.controller.*.*(..))")
    public void startLog(JoinPoint jp) {
        System.out.println("メソッド開始:" + jp.getSignature());
    }
}
After Returning
SampleAspect.java
package com.example.demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import com.example.demo.controller.resorces.UserResponse;
@Aspect
@Component
public class SampleAspect {
    @AfterReturning(value = "execution(public * com.example.demo.controller.*.*(..))", returning = "user")
    public void endLog(JoinPoint jp, UserResponse user) {
        System.out.println("メソッド正常終了:" + jp.getSignature());
        System.out.println("戻り値:" + user);
    }
}
After Throwing
SampleAspect.java
package com.example.demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SampleAspect {
    @AfterThrowing(value = "execution(public * com.example.demo.controller.*.*(..))", throwing = "e")
    public void endLog(JoinPoint jp, RuntimeException e) {
        System.out.println("メソッド異常終了:" + jp.getSignature());
        e.printStackTrace();
    }
}
After
SampleAspect.java
package com.example.demo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SampleAspect {
    @After("execution(public * com.example.demo.controller.*.*(..))")
    public void endLog(JoinPoint jp) {
        System.out.println("メソッド終了:" + jp.getSignature());
    }
}
Around
SampleAspect.java
package com.example.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SampleAspect {
    @Around("execution(public * com.example.demo.controller.*.*(..))")
    public Object log(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("メソッド開始:" + jp.getSignature());
        Object result;
        try {
            // 対象メソッド実行
            result = jp.proceed();
            System.out.println("メソッド終了:" + jp.getSignature());
            System.out.println("戻り値:" + result);
            return result;
        } catch (Throwable e) {
            System.out.println("メソッド異常終了:" + jp.getSignature());
            e.printStackTrace();
            throw e;
        }
    }
}
Pointcut
名前付きPointcut
pointcutに名前を付けて再利用することもできます。
SampleAspect.java
package com.example.demo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class SampleAspect {
    @Pointcut("execution(public * com.example.demo.controller.*.*(..))")
    public void demoController() {}
    @Before("demoController()")
    public void startLog(JoinPoint jp) {
        System.out.println("メソッド開始:" + jp.getSignature());
    }
}