spring AOPについて

Spring AOPについての個人的な備忘録です。

## 参考
[Spring 徹底入門](https://www.amazon.co.jp/Spring%E5%BE%B9%E5%BA%95%E5%85%A5%E9%96%80-Spring-Framework%E3%81%AB%E3%82%88%E3%82%8BJava%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BENTT%E3%83%87%E3%83%BC%E3%82%BF/dp/4798142476/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=spring&qid=1566716142&s=gateway&sr=8-3)
[【Spring】Spring AOPについて](https://hosochin.com/2022/06/06/post-1207/)

## Spring AOP
JoinPoint（指定したメソッドの実行前や実行後などのタイミング）に対して、@Aspectアノテーションを付与したクラスで実装した処理を差し込めます。

### 使用可能なAdviceのアノテーション
| アノテーション  |説明                |
|:---------------|:------------------|
| @Before        |対象のメソッドの実行前に処理が差し込まれる。|
| @AfterReturning|対象のメソッドが正常終了した後に処理が差し込まれる。正常終了時のメソッドの戻り値を取得することもできる。 |
| @AfterThrowing |対象のメソッドが異常終了(例外がスローされたとき)に処理が差し込まれる。異常終了時の例外を取得することもできる。|
| @After         |対象のメソッドが正常終了や例外のスローに関わらず、終了時に処理が差し込まれる。|
| @Around        |最も強いAdvice。対象のメソッドの前後に処理が差し込まれる。|


## 実装
### Before
```java: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
```java: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
```java: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
```java: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
```java: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に名前を付けて再利用することもできます。

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