我遵循教程https://spring.io/guides/gs/batch-processing/,它基本上读取了一个电子表格,并在应用程序启动后将数据插入数据库中。我想在每次引发休息服务时执行读取过程,所以我在这个应用程序中添加了一个控制器。为了调用这个工作,我遵循了How to trigger a job using a rest web service?中的建议,现在它引发了我的问题:每当我调用其余服务时,它只运行afterJob方法。我读了how to select which spring batch job to run based on application argument - spring boot java config(与我的问题有一定的相似性)和优秀的博客文章,但我仍然被卡住了。我想打电话给#34;公共ItemReader reader()"在休息服务之后,我希望在应用程序通过main()启动时完成相同的流程。我的意思是,与springboot部署时的流程相同。我想我的困惑在于@EnableBatchProcessing或JobExecutionListenerSupport,但我真的很困惑。 以下是最重要的摘录。
控制器
@Autowired
JobLauncher jobLauncher;
@Autowired
Job job;
@RequestMapping("/runit")
public void handle() throws Exception{
JobParameters jobParameters =
new JobParametersBuilder()
.addLong("time",System.currentTimeMillis()).toJobParameters();
jobLauncher.run(job, jobParameters);
}
监听
@Component
public class JobCompletionNotificationListener extends
JobExecutionListenerSupport {
@Override
public void afterJob(JobExecution jobExecution) {
if(jobExecution.getStatus() == BatchStatus.COMPLETED) {
批量配置
@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
// tag::readerwriterprocessor[]
@Bean
public ItemReader<Person> reader() {
FlatFileItemReader<Person> reader = new FlatFileItemReader<Person>();
reader.setResource(new ClassPathResource("sample-data.csv"));
reader.setLineMapper(new DefaultLineMapper<Person>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames(new String[] { "firstName", "lastName" });
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
setTargetType(Person.class);
}});
}});
return reader;
}
@Bean
public ItemProcessor<Person, Person> processor() {
return new PersonItemProcessor();
}
@Bean
public ItemWriter<Person> writer(DataSource dataSource) {
JdbcBatchItemWriter<Person> writer = new JdbcBatchItemWriter<Person>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Person>());
writer.setSql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)");
writer.setDataSource(dataSource);
return writer;
}
@Bean
public Job importUserJob(JobBuilderFactory jobs, Step s1, JobExecutionListener listener) {
return jobs.get("importUserJob")
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(s1)
.end()
.build();
}
@Bean
public Step step1(StepBuilderFactory stepBuilderFactory, ItemReader<Person> reader,
ItemWriter<Person> writer, ItemProcessor<Person, Person> processor) {
return stepBuilderFactory.get("step1")
.<Person, Person> chunk(10)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
application.properties
application.properties
# SPRING BATCH (BatchDatabaseInitializer)
spring.batch.job.enabled=false
spring.batch.initializer.enabled=false
答案 0 :(得分:4)
在深入讨论此问题的聊天之后,真正的“问题”是ItemReader
被创建一次,而不是每次REST调用创建一次(每次执行一次就称为一次)。要解决此问题,请将ItemReader
步骤作为范围。这将允许您在每次运行时获取阅读器的新实例,这也使得能够根据作业参数注入文件名。
从代码的角度来看,改变一下:
@Bean
public ItemReader<Person> reader() {
到此:
@Bean
@StepScope
public FlatFileItemReader<Person> reader() {
返回类型更改的原因是Spring Batch会自动为您注册ItemStream
。但是,当使用@StepScope
时,我们只会看到您定义的回报。在这种情况下,ItemReader
不会扩展/实施ItemStream
,因此我们不知道您正在返回我们应该自动注册的内容。通过返回FlatFileItemReader
,我们可以看到所有接口/等,并可以为您应用“魔法”。