簡體   English   中英

Spring Boot + AspectJ:為什么必須在事務開始工作之前編譯兩次代碼?

[英]Spring Boot + AspectJ: why code must be compiled twice, before transactions start working?

我正在使用帶有 AspectJ 1.9.7 (CTW) 的 Spring 引導 2.5.5。 我發現有時事務不會回滾,要解決這個問題,我只需要重新編譯代碼並再次運行它。 例如:

我有方法 addB() 持久化實體 B,方法 addC() 拋出異常和方法 A() 組合它們。 當我調用 A() 時,拋出異常,但實體 B 保留在數據庫中(如預期的那樣)。 當我用 @Transactional 注釋方法 A() 時,結果是相同的。 但是,如果我再次構建所有內容(沒有任何更改),那么事務將被回滾並且數據庫中沒有新記錄。

這是我的完整 POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.abcc</groupId>
    <artifactId>abcc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>abcc</name>
    <description>abcc</description>
    <properties>
        <java.version>11</java.version>
        <log4j2.version>2.15.0</log4j2.version>
        <aspectj.version>1.9.7</aspectj.version>
        <aspectj-maven-plugin.version>1.14.0</aspectj-maven-plugin.version>
    </properties>
    <dependencies>
        <!--SPRING-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <!--CACHE-->
        <dependency>
            <groupId>javax.cache</groupId>
            <artifactId>cache-api</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>3.8.1</version>
        </dependency>
        <!--DATABASE-->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.18.1</version>
        </dependency>
        <dependency>
            <groupId>org.assertj</groupId>
            <artifactId>assertj-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>6.0.19.Final</version>
        </dependency>
        <dependency>
            <groupId>org.passay</groupId>
            <artifactId>passay</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>2.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.sanctionco.jmail</groupId>
            <artifactId>jmail</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.10.13</version>
        </dependency>
        <!--AOP-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
    </dependencies>

    <profiles>
        <profile>
            <id>dev</id>
            <properties>
                <activatedProperties>dev</activatedProperties>
            </properties>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <activatedProperties>test</activatedProperties>
            </properties>
            <dependencies>
                <dependency>
                    <groupId>com.h2database</groupId>
                    <artifactId>h2</artifactId>
                    <version>1.4.191</version>
                </dependency>
            </dependencies>
        </profile>
    </profiles>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                    <excludeDevtools>false</excludeDevtools>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <trimStackTrace>false</trimStackTrace>
                </configuration>
            </plugin>
            <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>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <showWeaveInfo>true</showWeaveInfo>
                    <Xlint>ignore</Xlint>
                    <verbose>true</verbose>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <complianceLevel>${java.version}</complianceLevel>
                    <encoding>utf-8</encoding>
                    <outxml>true</outxml>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                    <excludes>
                        <exclude>**/*.java</exclude>
                    </excludes>
                    <forceAjcCompile>true</forceAjcCompile>
                    <sources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.outputDirectory}</weaveDirectory>
                    </weaveDirectories>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
</project>

這是非常奇怪的情況,我找不到相關信息。 你能幫忙找出原因嗎?

這是一個臨時答案,因為評論太有限,無法解釋我對 MCVE 的體驗。

我無法重現該問題,因為 IDEA 沒有找到 Lombok 設置器。 即使在運行之前將構建操作委托給 Maven,我也會得到NoSuchMethodError: '...TestEntity.setCode(java.lang.String)' 接下來,我將嘗試不使用 Lombok。 請注意,Lombok 和 AspectJ 不能互相配合,請在此處查看我的回答 或者,您也可以確保 Maven 執行以下任一操作:

  • 首先使用 Javac + Lombok 構建,然后在第二步中應用 AspectJ 二進制編織,全部在一個模塊中。
  • 與上面類似,但在模塊 A 中執行第一個構建步驟,在單獨的模塊 B 中執行第二個構建步驟。然后您將擁有一個未編織和一個編織工件,您可以根據自己的喜好使用它們。 例如,您還可以在啟動應用程序時通過加載時編織使用 unwoven one 和 appy 事務方面。 對於這兩種方法,請在此處查看我的其他答案
  • Delombok 源代碼在第二個構建步驟中使用 AspectJ 編譯器構建生成的源代碼。

我在 IDE 中生成了構造函數、getter 和 setter,而不是使用 Lombok。 現在項目在 IDE 和 Maven 中編譯。 它的行為與應有的完全一樣。 使用@Transactional ,創建 0 個實體,沒有它 2。

我不確定 Lombok 與 AspectJ 是否真的是由於使用 Lombok 注釋時的不可編譯性而導致的問題,但在沒有 Lombok 的情況下嘗試應該很容易。 如果它也適用於您的環境,我們找到了罪魁禍首,可以考慮實施上述 3 種方法之一。 然后你可以告訴我你這樣做是否有任何困難。

首先:您的多模塊方法在我的環境中完美運行。 但是后來我檢查了初始的 MCVE,當我完全刪除 Lombok 時,奇怪的行為並沒有消失。 在閱讀您的答案( 這個)時,我在 IntelliJ 設置(構建工具-> Z9115C10980645C41313F244AC1A37F和它應該開始工作)中檢查了“ Delegate IDE 構建/運行對 maven 的操作”。 在下一步中,我關閉了此選項並在運行配置中選中了“運行前不要構建”。 我不完全理解它(特別是為什么它在第二次嘗試后以舊方式工作),但你的評論幫助我實現了這一點。

我將研究 IntelliJ 行為(在兩種情況下,控制台 output 幾乎相同),但如果您知道它為什么會這樣工作,我會很高興聽到它。 你幫了我很多,謝謝!

摘要解決方案:我在我的應用程序的 IntelliJ 運行配置中啟用了“運行前不要構建”。 現在更改在第一次構建后起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM