Posted at

Spring Boot で TransactionManager に tx:advice の設定を反映する

More than 3 years have passed since last update.

Spring Boot で TransactionManager に <tx:advice>...</tx:advice> の設定を反映させる方法を調べたので、そのメモ書きです。

実現しようとしたのは、以下の内容です。



  1. @Transactional アノテーションをクラスあるいはメソッドに毎回記述するのは面倒なので、webapp.sample.service パッケージの下にあるクラスのメソッドは全て @Transactional アノテーションを付加しなくてもトランザクションの対象になるようにする。

  2. チェック例外発生時もロールバックされるようにする。

  3. トランザクションのタイムアウトも設定する。

Spring Boot を使用しない Spring Framework の場合であれば WEB-INF 直下に applicationContext.xml を作成して、その中に <tx:advice>...</tx:advice> と AOP の設定を記述して、web.xml に /WEB-INF/applicationContext.xml が読み込まれるように設定すればよいようなのですが、Spring Boot には WEB-INF ディレクトリも web.xml もありません。

Bean の設定は Bean定義ファイルではなく Java Configuration のクラス内で @Bean アノテーションを付加して記述するので、同様にプログラムで記述する方法があるのかと思い調べてみましたが、そのような情報も見つかりませんでした。

結局いろいろ調査した結果、以下の方法で実現できました。

まず <tx:advice>...</tx:advice> と AOP の設定を記述した Bean定義ファイル ( 今回は applicationContext.xml にしています ) を resources ディレクトリの下に作成します。


applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="Exception" timeout="3"/>
</tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="pointcutService" expression="execution(* webapp.sample.service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcutService"/>
</aop:config>

</beans>



  • Spring Boot では transactionManager という Bean が内部で定義済なので、Java Configuration のクラス内で明示的に定義する必要はありません。


  • webapp.sample.service..*.* の記述で webapp.sample.service パッケージの下にあるクラス全て ( サブパッケージの下のクラスも ) が対象になります。

次に @SpringBootApplication アノテーションの上に @ImportResource("classpath:applicationContext.xml") を追加します。


Application.java

package ksbysample.webapp.basic;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;

import java.text.MessageFormat;

@ImportResource("classpath:applicationContext.xml")
@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}


これで webapp.sample.service パッケージの下にあるクラスのメソッドは全て @Transactional アノテーションを記述しなくてもトランザクション対象になります。