Spring Batch应用出现JobRestController与SpringBatchConfig循环依赖如何解决
问题原因
Spring Boot 2.6+ 版本默认禁用了循环依赖支持,你当前项目的依赖循环路径如下:
JobRestController启动初始化时,需要注入Job实例Job是SpringBatchConfig配置类中通过@Bean方法声明的Bean,初始化Job前需要先完成SpringBatchConfig类的实例化SpringBatchConfig加了@AllArgsConstructor注解,需要通过构造函数注入ItemReader、ItemProcessor、ItemWriter三个Bean,而其中ItemReader的实现也是当前SpringBatchConfig类中声明的@Bean,必须等配置类实例化完成才能创建,二者形成初始化死锁,触发循环依赖报错。
解决方案
方案1(推荐:彻底消除循环)
修改SpringBatchConfig的写法,不要将依赖注入到配置类的成员变量中,改为将依赖声明为@Bean方法的入参,Spring会自动注入方法入参的Bean实例,修改后的代码参考:
import lombok.RequiredArgsConstructor; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.file.FlatFileItemReader; import org.springframework.batch.item.file.LineMapper; import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper; import org.springframework.batch.item.file.mapping.DefaultLineMapper; import org.springframework.batch.item.file.transform.DelimitedLineTokenizer; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; @Configuration @EnableBatchProcessing // 只注入两个工厂类即可,无需注入其他业务组件 @RequiredArgsConstructor public class SpringBatchConfig { private final JobBuilderFactory jobBuilderFactory; private final StepBuilderFactory stepBuilderFactory; // 把Step依赖直接声明为方法入参 @Bean public Job bankJob(Step stepLoadData) { return jobBuilderFactory.get("bank-data-loader-job") .start(stepLoadData) .build(); } // 把批量处理组件直接声明为方法入参 @Bean public Step stepLoadData(ItemReader<BankTransaction> bankTransactionItemReader, ItemProcessor<BankTransaction, BankTransaction> bankTransactionItemProcessor, ItemWriter<BankTransaction> bankTransactionItemWriter) { return stepBuilderFactory.get("step-load-data") .<BankTransaction, BankTransaction>chunk(100) .reader(bankTransactionItemReader) .processor(bankTransactionItemProcessor) .writer(bankTransactionItemWriter) .build(); } @Bean public ItemReader<BankTransaction> flatFileItemReader(@Value("${inputFile}") Resource inputFile) { FlatFileItemReader<BankTransaction> flatFileItemReader = new FlatFileItemReader<>(); flatFileItemReader.setName("CSV-READER"); flatFileItemReader.setLinesToSkip(1); flatFileItemReader.setResource(inputFile); flatFileItemReader.setLineMapper(lineMapper()); return flatFileItemReader; } @Bean public LineMapper<BankTransaction> lineMapper() { DefaultLineMapper<BankTransaction> lineMapper = new DefaultLineMapper<>(); DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer(); lineTokenizer.setDelimiter(","); lineTokenizer.setStrict(false); lineTokenizer.setNames("id", "accountID", "strTransactionDate", "transactionType", "amount"); lineMapper.setLineTokenizer(lineTokenizer); BeanWrapperFieldSetMapper<BankTransaction> fieldSetMapper = new BeanWrapperFieldSetMapper<>(); fieldSetMapper.setTargetType(BankTransaction.class); lineMapper.setFieldSetMapper(fieldSetMapper); return lineMapper; } }
如果你的ItemProcessor和ItemWriter是在其他配置类中声明的,确保Bean类型匹配,或者添加@Qualifier指定Bean名称即可。
方案2(快速修复,不推荐)
直接在项目的application.properties配置文件中添加如下配置,开启循环依赖支持:
spring.main.allow-circular-references=true
方案3(临时修复)
在JobRestController中注入Job的位置添加@Lazy注解,延迟Job的初始化时机:
@RestController @AllArgsConstructor public class JobRestController { private JobLauncher jobLauncher; @Lazy private Job job; // 其余代码保持不变 }
内容的提问来源于stack exchange,提问作者Elhilali Yassine
相关产品推荐
相关产品推荐

