【Spring Framework】@Transactional のメソッドはクラス内から呼ぶとトランザクションが実行されない

## やりたかったこと
下記のような感じで、1 メソッドでトランザクションを 2 回かけたかったです。
[公式ドキュメント](https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction-declarative-annotations)を読むと、public method に `@Transactional` が使えると書いてあるので、1 メソッドからトランザクションをかけるメソッドをそれぞれ呼び出しても大丈夫かと思い試してみたところ、どうやらこのサービスクラスをプロパティに持つクラスから `registerA` `registerB` をそれぞれ呼び出さないとトランザクションは効きませんでした。

```

@Service
@RequiredArgsConstructor
public class HogeHogeServiceImpl implements HogeHogeService {

  private final HogeHogeRepository hogehogeRepository;
  private final FugaFugaRepository fugafugaRepository;

  @Override
  public void registerAB(List<HogeHoge> hogehogeList) {
    List<FuaFuga> fugafugaList = registerA(hogehogeList);
    registerB(fugafugaList);
  }

  @Override
  @Transactional
  public List<FugaFuga> registerA(List<HogeHoge> hogehoegList) {
    try {
        ...いろいろな処理

      hogehogeRepository.register(hogehogeList);
        
        ...いろいろな処理

      return createSuccessFugaFugaList();
    } catch (Exception e) {
      return createFailedFugaFugaList();
    }

  }

  @Override
  @Transactional
  public void registerB(List<FugaFuga> hogehoegList) {
     ...いろいろな処理

    fugafugaRepository.register(fugafugaList);

  }

  ...
}

```

## `@Transactional` は Spring AOP を使ってる
なぜ `@Transactional` をメソッドにつけると、トランザクションが実行されるのでしょうか。
おそらく `TransactionManager` をどこかのタイミングで実行しているのだと思います。
`registerA` の処理の始めにコールスタックを吐き出すようにして、 `registerA` をサービスクラス外から呼び出して調べてみました。

```
  @Override
  @Transactional
  public List<FugaFuga> registerA(List<HogeHoge> hogehoegList) {
    Arrays.stream(Thread.currentThread().getStackTrace()).forEach(stackTraceElement -> {
      System.out.println("class name = " + stackTraceElement.getClassName());
      System.out.println("method name = " + stackTraceElement.getMethodName());
      System.out.println("-------------------------");
    });
  ...
  }
```

出力

```
class name = java.lang.Thread
method name = getStackTrace
-------------------------
class name = xxxx.xxxx.HogeHogeServiceImpl
method name = registerA
-------------------------
class name = xxxx.xxxx.HogeHogeServiceImpl$$FastClassBySpringCGLIB$$40a6490f
method name = invoke
-------------------------
class name = org.springframework.cglib.proxy.MethodProxy
method name = invoke
-------------------------
class name = org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation
method name = invokeJoinpoint
-------------------------
class name = org.springframework.aop.framework.ReflectiveMethodInvocation
method name = proceed
-------------------------
class name = org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation
method name = proceed
-------------------------
class name = org.springframework.transaction.interceptor.TransactionAspectSupport
method name = invokeWithinTransaction
-------------------------
class name = org.springframework.transaction.interceptor.TransactionInterceptor
method name = invoke
-------------------------
class name = org.springframework.aop.framework.ReflectiveMethodInvocation
method name = proceed
-------------------------
class name = org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation
method name = proceed
-------------------------
class name = org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor
method name = intercept
-------------------------
class name = xxxx.xxxx.HogeHogeServiceImpl$$EnhancerBySpringCGLIB$$8837d8e0
method name = registerA
-------------------------
class name = yyyy.yyyy.HogeHogeController
method name = run
-------------------------
```

これだけだと`TransactionManager` をどのタイミングで使っているか分かりません。
出力されるまでに、 `org.springframework.aop.framework.CglibAopProxy` が使われているのが分かりました。パッケージパスを見た限り Spring AOP を使ってそうです。

### Spring AOP
Spring AOP は、アスペクト指向プログラミングを実現するフレームワークで、これにより Spring Bean でのクラス・メソッドの前後に処理を追加することができます。
例えば、すべてのコントローラのメソッドでリクエストを受け取るたびにリクエストの中身をログ出力する、といったことが簡単に実現できます。

[Aspect Oriented Programming with Spring](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop)

`@Transactional` は Spring AOP を使っています。というのも、コールスタックを確認して呼び出されているクラス・メソッドを追わなくても、公式ドキュメントに説明が書いてありました。

[Understanding the Spring Framework’s Declarative Transaction Implementation](https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#tx-decl-explained)

`@Transactional`を使うと、 AOP Proxy を介してトランザクションが有効になり `TransactionInterceptor` クラスによってトランザクション実行・コミット・ロールバックが制御されるようです。
トランザクションが有効にならないのは、AOP Proxy の制御が関係ありそうなので、AOP プロキシについて調べてみます。

### AOP Proxy
Spring AOP は Dynamic Proxy または CGLIB を使って Proxy をベースに作られています。
インターフェースを実装したクラスでは Dynamic Proxy が使われるようです。
Proxy とは何なのか調べてみます。

[Proxying Mechanisms](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-proxying)

### Proxy
Proxy とは Java標準クラスの [java.lang.reflect.Proxy](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Proxy.html) のことです。
Proxy を使うことで、特定のクラス・メソッドの前後に処理を追加することが可能です。
`InvocationHandler` の実装クラスを用意して、対象のクラス・メソッドの前後での処理をメソッドで書きます。
handler を引数で渡して、Proxy を使って対象のクラスをインスタンス生成してメソッド呼び出すと、対象のメソッドに加えて前後の処理が実行されます。

```
public class ProxySample {

  public static void main(String[] args) {
    HogeHogeInvocationHandler handler = new HogeHogeInvocationHandler(new HogeHogeImpl());
    HogeHoge hogeHoge = (HogeHoge) Proxy
        .newProxyInstance(HogeHoge.class.getClassLoader(), new Class<?>[]{HogeHoge.class}, handler);
    hogeHoge.run();
  }

}

interface HogeHoge {

  void run();
}

class HogeHogeImpl implements HogeHoge {

  @Override
  public void run() {
    System.out.println("hoge hoge");
  }
}

class HogeHogeInvocationHandler implements InvocationHandler {

  private HogeHoge hogeHoge;

  HogeHogeInvocationHandler(HogeHoge hogeHoge) {
    this.hogeHoge = hogeHoge;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("before");
    Object o = method.invoke(this.hogeHoge, args);
    System.out.println("after");
    return o;
  }
}
```

出力

```
before
hoge hoge
after
```

以下のように、public method から別の public method を呼び出すようにしても、クラス内から呼び出した場合は proxy を介さないので、前後の処理は `run2` では実行されません。

```
class HogeHogeImpl implements HogeHoge {

  @Override
  public void run() {
    System.out.println("hoge hoge");
    run2();
  }

  @Override
  public void run2() {
    System.out.println("hoge hoge 2");
  }
}
```

出力

```
before
hoge hoge
hoge hoge 2
after
```

Spring AOP もこの Proxy 同様に、前後の処理を呼び出すのに AOP Proxy を介さないといけないので、クラス内で `@Transactional` がついたメソッドを呼び出してもトランザクションは有効になりません。

[Understanding AOP Proxies](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-understanding-aop-proxies)

## まとめ
- `@Transactional` は Spring AOP を、つまり Dynamic Proxy (または CGLIB) を使ってる
- Proxy によるメソッドの前後での処理を実行したいなら、クラス内から対象のメソッドを呼び出すのではなく、DIした他クラスから呼び出さないといけない
- なので、それぞれのメソッドでトランザクションを実行したいなら、DIされた他クラスからそれぞれ呼び出すか、別クラスに移してそれぞれ呼び出すと良い