javaspringdependency-injectionspring-transactions

How to do self injection Spring Boot 3+, in order to pass through proxy and apply transactional behavior


I'd like to create a self reference in my service so that I can use it to go through Spring's proxy and apply transactional behavior.

@RequiredArgsConstructor
public class Service {
  @Lazy private final Service self;

  public void foo() {
    self.bar();
  }

  @Transactional
  public void bar() {
    // do some transactional stuff
  }
}

I want to do that also to be compliant with java:S6809

A method annotated with Spring’s @Async or @Transactional annotations will not work as expected if invoked directly from within its class.
This is because Spring generates a proxy class with wrapper code to manage the method’s asynchronicity (@Async) or to handle the transaction (@Transactional). However, when called using this, the proxy instance is bypassed, and the method is invoked directly without the required wrapper code.

The issue is that I cannot do it otherwise I get an error on startup

The dependencies of some of the beans in the application context form a cycle:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

Is setting spring.main.allow-circular-references to true the only solution to do self-injection in Spring?

(some references: https://medium.com/javarevisited/spring-transactional-mistakes-everyone-did-31418e5a6d6b)


Solution

  • You can try TransactionTemplate instead of @Transactional

    @RequiredArgsConstructor
    class MyService {
        @Lazy
        private final MyService self;
        private final TransactionTemplate transactionTemplate;
    
    
        public void foo() {
            self.bar();
        }
    
        public void bar() {
            transactionTemplate.executeWithoutResult(ts -> {
                // do tx stuff
            });
        }
    }
    
    

    see https://docs.spring.io/spring-framework/reference/data-access/transaction/programmatic.html