升级Spring Boot 3.4.3与Batch 5.2.1后事务管理器Bean创建失败
错误原因
Spring Boot 3.4.x版本新增了TransactionExecutionListenersAutoConfiguration,会自动为所有PlatformTransactionManager类型的Bean注入ExecutionListenersTransactionManagerCustomizer,但你手动定义的platformTxManager(类型为ResourcelessTransactionManager)的transactionExecutionListeners属性要求Collection<TransactionExecutionListener>类型,无法直接转换Customizer实例,导致Bean创建失败。
可行解决方案
方案一:禁用事务执行监听器自动配置
在应用配置文件(application.properties或application.yml)中添加排除配置,阻止Spring Boot自动注入相关自定义器:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.transaction.TransactionExecutionListenersAutoConfiguration
方案二:使用Spring Batch自动配置的事务管理器
删除beans.xml中手动定义的platformTxManager,修改BatchConfig的注解,让Spring Batch自动适配事务管理器:
@Configuration @EnableBatchProcessing(dataSourceRef = "customDaoDataSource") public class BatchConfig { }
Spring Batch会根据指定的数据源自动创建适配的事务管理器,避免手动定义带来的配置冲突。
方案三:显式设置空的事务执行监听器集合
在beans.xml中为platformTxManager显式配置空的transactionExecutionListeners集合,覆盖自动注入的内容:
<bean id="platformTxManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"> <property name="transactionExecutionListeners"> <list/> </property> </bean>
方案四:替换为Spring Boot兼容的事务管理器
如果批处理作业允许使用带数据源的事务管理器,将ResourcelessTransactionManager替换为DataSourceTransactionManager,并调整相关代码:
- 修改
beans.xml中的platformTxManager定义:
<bean id="platformTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="customDaoDataSource"/> </bean>
- 修改
BatchJob1Configuration,注入容器中的事务管理器而非手动实例化:
@Configuration public class BatchJob1Configuration { @Autowired private JobRepository jobRepository; @Autowired private PlatformTransactionManager platformTxManager; private String jobName = "something"; private String stepName = "something"; @Bean public Step batchJob1Step1() { return new StepBuilder(stepName, jobRepository) .<JSONObject, List<Info>>chunk(10, platformTxManager) .reader(getReader()) .processor(getProcessor()) .writer(getWriter()) .faultTolerant() .retryLimit(2) .retry(Exception.class) .skipLimit(10) .skip(Exception.class) .listener(new GenericSkipListener(jobName, stepName)) .build(); } }
内容的提问来源于stack exchange,提问作者mogli5

