Resolving BeanNotOfRequiredTypeException in Custom Spring Transaction Configuration
When configuring multiple transaction managers in a Spring Boot application, you may encounter the following error:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'defaultTx' is expected to be of type 'org.springframework.transaction.PlatformTransactionManager' but was actually of type 'org.springframework.transaction.support.TransactionTemplate'
This exception occurs because a bean intended to serve as the default transaction manager is actually defined as a TransactionTemplate. Spring’s transaction infrastructure expects a PlatformTransactionManager when resolving the transaction manager for declarative transaction management (e.g., @Transactional).
Consider the following improper bean definitions that expose TransactionTemplate instances under names reserved for transaction managers:
@Bean(name = "primaryTx")
@Primary
public TransactionTemplate primaryTxTemplate(@Qualifier("primaryDS") DataSource ds) {
DataSourceTransactionManager txManager = new DataSourceTransactionManager(ds);
return new TransactionTemplate(txManager);
}
@Bean(name = "secondaryTx")
public TransactionTemplate secondaryTxTemplate(@Qualifier("secondaryDS") DataSource ds) {
DataSourceTransactionManager txManager = new DataSourceTransactionManager(ds);
return new TransactionTemplate(txManager);
}
Here, beans named primaryTx and secondaryTx are of type TransactionTemplate. If any component (like the Spring transaction auto-configuration) attempts to retrieve a PlatformTransactionManager by that name, the type mismatch leads to BeanNotOfRequiredTypeException.
To fix this, define beans that directly return the concrete transaction manager implementation (DataSourceTransactionManager), and ensure the bean names match what the consumer expects:
@Bean(name = "primaryTxManager")
@Primary
public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDS") DataSource ds) {
return new DataSourceTransactionManager(ds);
}
@Bean(name = "secondaryTxManager")
public PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryDS") DataSource ds) {
return new DataSourceTransactionManager(ds);
}
Now the beans are of the correct type. If you need a programmatic TransactionTemplate, you can create a separate bean that injects the appropriate PlatformTransactionManager, rather than exposing the template under the transaction manager’s bean name.