Spring Batch 4.3.x升级至5.0.x时自定义Mongo Job仓库遇dataSource缺失问题
我正将基于MongoDB Job仓库的Spring Boot 2.7.x(Spring Batch 4.3.x)项目迁移至Spring Boot 3.0.x(Spring Batch 5.0.x),已经自定义了JobRepository和TransactionManager等配置,但启动时一直报错要求存在dataSource Bean,即使已经排除了DataSource自动配置。
现有配置代码
自定义Job仓库和事务管理器配置
@Configuration public class MainBatchConfigurer { @Autowired private ExecutionContextDao mongoExecutionContextDao; @Autowired private JobExecutionDao mongoJobExecutionDao; @Autowired private JobInstanceDao mongoJobInstanceDao; @Autowired private StepExecutionDao mongoStepExecutionDao; @Bean public JobRepository jobRepo() { return new SimpleJobRepository(mongoJobInstanceDao, mongoJobExecutionDao, mongoStepExecutionDao, mongoExecutionContextDao); } @Bean public PlatformTransactionManager getTransactionManager() { return new ResourcelessTransactionManager(); } public TaskExecutorJobLauncher getJobLauncher() throws Exception { TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher(); jobLauncher.setJobRepository(jobRepo()); jobLauncher.afterPropertiesSet(); return jobLauncher; } @Bean public JobExplorer getJobExplorer() { return new SimpleJobExplorer(mongoJobInstanceDao, mongoJobExecutionDao, mongoStepExecutionDao, mongoExecutionContextDao); } }
基础配置
@Configuration public class BaseConfiguration { @Autowired private JobRepository jobRepo; @Autowired private PlatformTransactionManager getTransactionManager; protected StepBuilder getStep(String stepName) { return new StepBuilder(stepName, jobRepo); } protected JobBuilder getJob(String jobName) { return new JobBuilder(jobName,jobRepo); } }
示例Job类
@Configuration @EnableBatchProcessing public class DepartmentJob extends BaseConfiguration { @Autowired private PlatformTransactionManager getTransactionManager; // additional configuration @Bean public Step departmentMigrationStep() throws UnexpectedInputException, ParseException { return super.getStep("departmentMigrationStep ") .<xxx, yyy>chunk(10000,getTransactionManager) .reader(departmentPeekingReader()) .processor(departmentProcessor()) .writer(departmentWriter) .listener(genericItemReadListener) .listener(departmentSkipListener) .listener(genericStepExecutionListener) .listener(genericChunkListener) .build(); } @Bean public Job processDepartment() { return super.getJob("processDepartment") .incrementer(new RunIdIncrementer()).listener(deparmentJobListener()) .start(departmentMigrationStep ()) .build(); }
测试类
@RunWith(SpringRunner.class) @SpringBootTest @EnableBatchProcessing @EnableAutoConfiguration(exclude = DataSourceAutoConfiguration.class) public class DepartmentTest { @Autowired private JobLauncher jobLauncher; @Test public void department_migration() throws Exception { JobExecution jobExecution = jobLauncher.run(xxx.processDepartment(), jobParameters); } }
报错信息
启动测试和应用时均出现类似异常:
Unsatisfied dependency expressed through field 'jobRepo': Error creating bean with name 'jobRepository': Cannot resolve reference to bean 'dataSource' while setting bean property 'dataSource' ... Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'dataSource' available
启动应用时的提示:
APPLICATION FAILED TO START Description: A component required a bean named 'dataSource' that could not be found. Action: Consider defining a bean named 'dataSource' in your configuration.
解决方案
核心原因
@EnableBatchProcessing注解在Spring Batch 5.x中默认会触发基于JDBC的JobRepository自动配置流程,这个流程会强制寻找DataSource Bean,和自定义的MongoDB实现产生冲突。另外,自定义的JobLauncher没有被注册为Bean,导致Spring可能还是尝试使用默认的Launcher依赖JDBC版本的JobRepository。
修改步骤
移除所有类上的
@EnableBatchProcessing注解
删除DepartmentJob和DepartmentTest类上的@EnableBatchProcessing,避免触发默认的JDBC JobRepository自动配置。为自定义JobLauncher添加
@Bean注解
修改MainBatchConfigurer中的getJobLauncher方法,使其被Spring识别为Bean:
@Bean public TaskExecutorJobLauncher getJobLauncher() throws Exception { TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher(); jobLauncher.setJobRepository(jobRepo()); jobLauncher.afterPropertiesSet(); return jobLauncher; }
- 统一JobRepository的Bean名称
Spring Batch默认会寻找名为jobRepository的Bean,将自定义的JobRepository方法名改为jobRepository,或者指定Bean名称:
// 方法一:修改方法名 @Bean public JobRepository jobRepository() { return new SimpleJobRepository(mongoJobInstanceDao, mongoJobExecutionDao, mongoStepExecutionDao, mongoExecutionContextDao); } // 方法二:指定Bean名称 @Bean(name = "jobRepository") public JobRepository jobRepo() { return new SimpleJobRepository(mongoJobInstanceDao, mongoJobExecutionDao, mongoStepExecutionDao, mongoExecutionContextDao); }
同时,BaseConfiguration中的注入也要对应修改为jobRepository(如果用方法一的话):
@Autowired private JobRepository jobRepository; protected StepBuilder getStep(String stepName) { return new StepBuilder(stepName, jobRepository); } protected JobBuilder getJob(String jobName) { return new JobBuilder(jobName, jobRepository); }
- 规范TransactionManager的命名
将BaseConfiguration和DepartmentJob中的TransactionManager变量名改为更清晰的transactionManager,避免命名混淆:
// BaseConfiguration中 @Autowired private PlatformTransactionManager transactionManager; // DepartmentJob中 @Autowired private PlatformTransactionManager transactionManager; // Step构建时修改为 .<xxx, yyy>chunk(10000, transactionManager)
完成以上修改后,Spring会使用自定义的MongoDB版本JobRepository,不再尝试寻找DataSource Bean。
内容的提问来源于stack exchange,提问作者Giri

