0

I'm working on a Spring Batch project and I have a StackOverflowError with this Bean.

@Bean
@Primary
public JtaTransactionManager transactionManager(UserTransaction userTransaction,
        TransactionManager transactionManager) {
    JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, transactionManager);
    jtaTransactionManager.setAllowCustomIsolationLevels(true);
    return jtaTransactionManager;
}

If I changed the function name with transactionManager2 for example, it solve my error but I don't know why. Someone can tell me why and suggest a better option ? Thanks.

4
  • Not sure about the stackOverflowError but one problem I definitely see is param TransactionManager transactionManager is also with bean bane "transationManager" and since the method name is same its also trying to create bean with same. Commented Oct 16, 2024 at 12:21
  • I think it's something like that, but when I try to rename transationManager in parameters, nothing changes Commented Oct 16, 2024 at 13:27
  • You already had a transaction manager. Why are you creating another transaction manager using the same transaction manager and then making it primary. That's the one creating the circular dependency. Commented Oct 16, 2024 at 13:48
  • Which JTA provider do you use? Commented Oct 16, 2024 at 15:23

3 Answers 3

1

The JtaTransactionManager does not implement the Java Transaction API, it just delegates the management of distributed transactions to a third-party provider, such as the WildFly or Jakarta application server. This means that you are already supposed to have a bean in your application context that implements the TransactionManager interface. However, the circular dependency means that the transactionManager bean that you want to receive as a parameter for the transactionManager() method is the same bean that the transactionManager() method should return. This means that there are no other transaction managers in your application. This can happen if you run your application outside of the application server, or if you remove the dependency on the library that implements JTA.

Sign up to request clarification or add additional context in comments.

Comments

0

The issue you’re encountering is related to Spring's @Primary annotation and bean resolution.

How the Circular Dependency Arises

  • Default Wiring by Type: By naming the method transactionManager, Spring might infer that you are providing a default TransactionManager for the application, and it could lead to an implicit circular dependency if other beans depend on TransactionManager.

  • Spring's Bean Resolution: Spring resolves beans by both name and type. Since the name of your bean matches the TransactionManager type, Spring might attempt to inject this bean in other places, causing a circular dependency.

Suggested Solutions

  1. Use @Qualifier for Explicit Wiring

If you have multiple TransactionManager beans, you can resolve ambiguity by explicitly specifying which one to use in each case. You can use @Qualifier to instruct Spring where and which TransactionManager to use:

@Bean
@Primary
public JtaTransactionManager jtaTransactionManager(UserTransaction userTransaction, 
                                                   @Qualifier("customTransactionManager") TransactionManager transactionManager) {
    JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, transactionManager);
    jtaTransactionManager.setAllowCustomIsolationLevels(true);
    return jtaTransactionManager;
}

2. Lazy Initialization

Another approach is to use @Lazy on your TransactionManager bean. Spring will delay the initialization of the JtaTransactionManager bean until it’s explicitly needed, which may help break the circular dependency

@Bean
@Primary
@Lazy
public JtaTransactionManager transactionManager(UserTransaction userTransaction, 
                                                TransactionManager transactionManager) {
    JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, transactionManager);
    jtaTransactionManager.setAllowCustomIsolationLevels(true);
    return jtaTransactionManager;
}

By using @Qualifier, @Lazy, you should be able to avoid circular dependencies.

1 Comment

Thanks, but with @Lazy, I have exception anyway
0

I have tried your suggestions and here is that I can say.

@Qualifier and @Lazy doesn't work. @Bean(name = "transactionManager2") is a right solution but with Andrey answer I choice this :

@Bean
@Primary
public JtaTransactionManager jtaTransactionManager(UserTransaction userTransaction,
                                                   TransactionManager transactionManager) {
    JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
    jtaTransactionManager.setUserTransaction(userTransaction);
    jtaTransactionManager.setTransactionManager(transactionManager);
    jtaTransactionManager.setAllowCustomIsolationLevels(true);
    return jtaTransactionManager;
}

Thanks for your help.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.