1. 程式人生 > >Spring mode = "aspectj" 配置事務報錯

Spring mode = "aspectj" 配置事務報錯

程式碼環境

Spring4.3.7 + Hibernate5.1.4 + Jpa

意圖

配置宣告式事務.
Spring 事務管理中, 開啟註解驅動< tx:annotation-driven />

問題

使用預設基於代理的方式配置, 事務生效, 想要使用基於aspectj 模式, 配置, Service程式碼都無誤, 但是就是報錯.
jars :

  • spring-aspects
  • spring-aspects
  • aspectjrt
<tx:annotation-driven transaction-manager="transactionManager"
mode="aspectj" />

錯誤資訊

javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:282
) at com.sun.proxy.$Proxy33.persist(Unknown Source)

血淚

跟蹤程式碼發現, EntityManager 拿不到事務, 卻想做persist 操作, spring 換成4.0.0, 不會報錯, 但是事務無效, 不會真正執行儲存操作, 這個問題折磨了我好幾天, 最後終於從同事那兒get 到.

原因

點開mode=”aspectj”, 發現Spring有這麼一段

AspectJ weaving requires spring-aspects.jar on the classpath,
as well as load-time weaving (or compile-time weaving) enabled.

也就是說使用spring-aspects.jar 的aspectj, 需要指定編織時間, 使用編譯時織入.
aspectj 是靜態織入的, 也就是編譯期織入、類載入期織入(LTW), 編譯期織入可以採用編輯器(maven, ant)等工具, 類載入器可以通過類載入器,在類位元組碼載入到JVM時,織入切面.
這裡提供通過maven,指定spring-aspectj通過編譯時織入事務程式碼, 在pom.xml新增

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>${aspectj-maven-plugin.version}</version>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
    </dependencies>
    <configuration>
        <complianceLevel>1.8</complianceLevel>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
            </goals>
        </execution>
    </executions>
</plugin>

編譯完成後, 在class檔案可以看到 service 中加入以下程式碼

AnnotationTransactionAspect var10000 = AnnotationTransactionAspect.aspectOf();
...
var10000.ajc$around$org_springframework_transaction_aspectj_AbstractTransactionAspect$1$2a73e96c(this, new UserService$AjcClosure1(var4), ajc$tjp_0);

這就是aspectj自動完成程式碼編織, 加入事務管理.

做插入修改,操作,無誤,不再報錯…

後續再出現異常繼續發在這裡, 未完待續…