Spring Boot向Spring Batch传递参数至Writer的问题求助
我帮你分析下问题根源,再给出具体的解决办法:
问题核心原因
你的Writer类虽然加了@StepScope和@Value注解,但没有被Spring容器管理——在BatchConfig里你是直接通过new Writer(userDao)创建实例的,这种方式创建的对象,Spring不会处理它的任何注解,自然拿不到Job参数值。
另外补充个小问题:你的BatchConfig里直接用@Value("#{jobParameters['key']}")注入参数也是错误的,配置类是应用启动时就初始化的,而Job参数是在Job执行时才传入的,这里会导致启动阶段就找不到参数报错,建议直接删掉这部分代码。
解决方案
我们需要让Writer成为Spring管理的Bean,借助@StepScope延迟初始化来获取Job参数:
1. 调整Writer类
保留@StepScope,通过Spring支持的方式注入Job参数:
@StepScope @Component // 让Spring扫描并管理这个Bean public class Writer implements ItemWriter<UserDTO> { private UserDao userDao; private String key; // 构造函数注入UserDao public Writer(UserDao userDao) { this.userDao = userDao; } // 注入Job参数 @Value("#{jobParameters['key']}") public void setKey(String key) { this.key = key; } @Override public void write(List<? extends UserDTO> items) throws Exception { // 现在可以正常使用key参数了 System.out.println("获取到的key参数值:" + key); userDao.writePnoFile(items); } }
2. 修改BatchConfig类
不再手动new Writer,而是注入Spring管理的Writer Bean:
@Configuration @EnableBatchProcessing public class BatchConfig { @Value("${path.to.react.file}") private Resource resource; @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; @Autowired UserDao userDao; @Autowired // 注入Spring管理的Writer Bean private Writer writer; @Bean public Job job() { return jobBuilderFactory.get("readCSVFilesJob") .incrementer(new RunIdIncrementer()) .start(step()) .build(); } @Bean public Step step() { return stepBuilderFactory.get("step1").<UserDTO, UserDTO>chunk(100) .reader(Reader.reader(resource)) .processor(new Processor()) .writer(writer) // 使用注入的Writer,而非手动new .build(); } }
如果不想给Writer加@Component,也可以在BatchConfig里用@Bean定义Writer(二选一即可):
@Bean @StepScope public Writer writer(UserDao userDao, @Value("#{jobParameters['key']}") String key) { Writer writer = new Writer(userDao); writer.setKey(key); return writer; }
3. 控制器代码保留不变
你的控制器代码已经正确传递了key参数到JobParameters,这部分无需修改:
@GetMapping("/load/{id}") public BatchStatus load (@PathVariable String id) throws JobExecutionException { JobParameters jobParameters = new JobParametersBuilder() .addLong("time", System.currentTimeMillis()) // 保证每次Job实例唯一 .addString("key", id).toJobParameters(); JobExecution jobExecution = jobLauncher.run(job, jobParameters); return jobExecution.getStatus(); }
关键说明
@StepScope的作用是让Bean在Step执行阶段才初始化,这样就能获取到Job执行时传入的参数,而不是在应用启动时就提前初始化。只有被Spring容器管理的Bean,Spring才会处理它的@StepScope和@Value注解,所以绝对不能手动new对象。
这样修改后,你的Writer应该就能正常获取到key参数了。
内容的提问来源于stack exchange,提问作者Waley

