Spring Boot
AspectJ
Transactions
Configuration
AOP

How to configure spring boot application to use aspectj transactions?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Spring Boot transaction management usually works with proxy-based AOP, but some applications need stronger interception semantics. AspectJ transactions can advise methods that proxies miss, such as self-invocation paths or non-public execution points. This guide shows a practical setup for enabling AspectJ transaction advice in a Spring Boot project.

When AspectJ Is the Right Choice

Proxy-based transactions are simple and fast to adopt, but they have known boundaries. If a method inside a class calls another @Transactional method in the same class, proxy advice is bypassed. AspectJ weaving can solve that because advice is applied to bytecode execution points directly.

AspectJ is useful when you need:

  • Reliable advice on self-invoked transactional methods.
  • Broader interception than public proxy entry points.
  • Consistent behavior in complex service layering.

The tradeoff is additional build or runtime weaving complexity. Use it only when proxy limits block correctness.

Core Spring Configuration

First, add required dependencies and enable transaction management in AspectJ mode.

xml
1<!-- pom.xml -->
2<dependencies>
3    <dependency>
4        <groupId>org.springframework.boot</groupId>
5        <artifactId>spring-boot-starter-data-jpa</artifactId>
6    </dependency>
7    <dependency>
8        <groupId>org.springframework</groupId>
9        <artifactId>spring-aspects</artifactId>
10    </dependency>
11    <dependency>
12        <groupId>org.aspectj</groupId>
13        <artifactId>aspectjweaver</artifactId>
14    </dependency>
15</dependencies>

Then configure Spring:

java
1import org.springframework.context.annotation.Configuration;
2import org.springframework.transaction.annotation.EnableTransactionManagement;
3import org.springframework.context.annotation.AdviceMode;
4
5@Configuration
6@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
7public class TransactionConfig {
8}

That annotation switches transaction advice from proxy mode to AspectJ advice mode.

Weaving Options: Load-Time or Compile-Time

AspectJ requires weaving. Two common strategies are load-time weaving and compile-time weaving.

Load-time weaving is easier to introduce in many Boot services. Start the JVM with a java agent:

bash
java -javaagent:/path/to/aspectjweaver.jar -jar app.jar

For local development, add this to your run configuration so behavior matches production.

Compile-time weaving can reduce startup surprises because woven classes are produced at build time. Example Maven plugin setup:

xml
1<build>
2  <plugins>
3    <plugin>
4      <groupId>dev.aspectj</groupId>
5      <artifactId>aspectj-maven-plugin</artifactId>
6      <version>1.14</version>
7      <configuration>
8        <complianceLevel>17</complianceLevel>
9        <source>17</source>
10        <target>17</target>
11        <showWeaveInfo>true</showWeaveInfo>
12      </configuration>
13      <executions>
14        <execution>
15          <goals>
16            <goal>compile</goal>
17            <goal>test-compile</goal>
18          </goals>
19        </execution>
20      </executions>
21    </plugin>
22  </plugins>
23</build>

Pick one approach and document it clearly. Mixed strategies across environments are a common source of confusion.

Verifying Transaction Behavior

After setup, verify that a self-invoked transactional call is actually wrapped in a transaction.

java
1import org.springframework.stereotype.Service;
2import org.springframework.transaction.annotation.Transactional;
3import org.springframework.transaction.support.TransactionSynchronizationManager;
4
5@Service
6public class BillingService {
7
8    public void runBillingFlow() {
9        // Self invocation still receives advice when AspectJ weaving is active.
10        persistInvoice();
11    }
12
13    @Transactional
14    void persistInvoice() {
15        boolean active = TransactionSynchronizationManager.isActualTransactionActive();
16        if (!active) {
17            throw new IllegalStateException("Transaction is not active");
18        }
19        // Write to database here.
20    }
21}

In integration tests, assert both success paths and rollback paths. A passing happy path alone does not prove transaction boundaries are correct.

Observability and Testing Strategy

For transaction bugs, observability is as important as configuration. Log transaction boundaries in integration tests and include correlation identifiers so database writes can be traced end to end. In Spring tests, verify rollback behavior by forcing a checked and an unchecked exception path, then asserting final table state.

You can also add a lightweight health assertion at startup that checks whether expected transaction aspects are present. This does not replace functional tests, but it catches wiring mistakes early during deployment. Combined with SQL-level assertions, this gives high confidence that AspectJ weaving and transaction semantics remain stable over refactors.

Common Pitfalls

A frequent mistake is enabling AdviceMode.ASPECTJ without adding aspectjweaver. In that state, configuration looks correct but advice never executes.

Another common issue is forgetting the java agent when using load-time weaving. The app boots, but methods are not woven, which leads to false confidence.

Teams also struggle when one environment uses compile-time weaving and another uses load-time weaving. Behavior can diverge in subtle ways. Standardize one approach per service.

Finally, verify method visibility assumptions. AspectJ can advise broader join points, but if you refactor code and change package structure, pointcuts and weaving diagnostics may change. Keep weave info enabled while rolling out.

Summary

  • Use AspectJ transactions when proxy mode misses required execution points.
  • Add spring-aspects and aspectjweaver, then enable AdviceMode.ASPECTJ.
  • Configure either load-time or compile-time weaving and keep it consistent.
  • Validate with integration tests that transaction activation and rollback both work.
  • Keep weaving diagnostics visible during initial adoption.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.