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.
@Lazy
lombok.copyableAnnotations += org.springframework.context.annotation.Lazy
in lombok.config
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)
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