在Spring Batch的步骤之间传递值时,出现空指针异常

问题描述 投票:0回答:1

我正在学习Spring Batch,并且正在做一个示例程序,在该程序中,我需要将值从一个步骤传递到另一个步骤。

场景:我有一个人员表,在其中从中提取人员详细信息,将几列保存到DTO(在步骤1的ItemWriter中),并将值从DTO传递到where子句中的另一个表,用于从中提取相关值(在第2步的ItemReader中)。最后,我将使用所有这些值生成一个CSV。

这是我的代码:

@Bean
    public Job job() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception {
        return jobBuilderFactory.get("readDBJob").incrementer(new RunIdIncrementer()).start(step1()).next(step2())
                .build();
    }

@Bean
public Step step1() {
    return stepBuilderFactory.get("step1").<Person, Person>chunk(500000).reader(itemReader())
            .writer(itemWriter()).listener(promotionListener()).build();
}

@Bean
    public Step step2() throws UnexpectedInputException, ParseException, NonTransientResourceException, Exception {
        return stepBuilderFactory.get("step2").<Person, Result>chunk(100)
                .reader(readingObjectItemReader.cursorReader()).writer(itemWriterForStep2()).build();
    }

第1步的ItemWriter:

        @Bean
public ItemWriter<Person> itemWriter() {
    return new ItemWriter<Person>() {

        private StepExecution stepExecution;
        List<personDTO> responseList = null;

        @Override
        public void write(List<? extends Person> items) throws Exception {
            for (Person item : items) {
                personDTO responseObject = new personDTO();
                BeanUtils.copyProperties(item, responseObject);
                if(responseObject != null && responseObject.getPersonId() != null) {
                    if(stepExecution.getExecutionContext().containsKey("personDtoObject")) {
                        responseList = (List<personDTO>) this.stepExecution.getExecutionContext().get("personDtoObject");
                    } else {
                        responseList = new ArrayList<personDTO>();
                    }
                    responseList.add(responseObject);
                    this.stepExecution.getExecutionContext().put("personDtoObject", responseList);
                }
            }
        }

        @BeforeStep
        public void saveStepExecution(StepExecution stepExecution) { this.stepExecution = stepExecution; }
    };
}

作业执行上下文:

    @Bean
    public Object promotionListener() { 
        ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
        listener.setKeys(new String[] {"personDtoObject"});
        listener.setStrict(true);
        return listener;
    }

这是我尝试在步骤2 ItemReader中访问值的方式

公共类ReadingObjectItemReader实现ItemReader {

@Autowired
DataSource dataSource;

private List<personDTO> personDtoList;

String value;


@Override
public personDetails read()
        throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
    return null;
}

@Bean
public JdbcCursorItemReader<personDetails> cursorReader() {

    System.out.println("Values from the step 1 " + personDtoList);
    ....
}

@BeforeStep
public void retrieveSharedData(StepExecution stepExecution) {
    JobExecution jobExecution = stepExecution.getJobExecution();
    ExecutionContext jobContext = jobExecution.getExecutionContext();
    personDtoList=  (List<personDTO>) jobContext.get("personDtoObject");
}

}

[当我尝试在步骤2中访问personDtoList的值时,我得到的是null。我在步骤1完成之前验证了StepContext中的值,直到那里一切都看起来不错,但是当尝试在步骤2中访问它们时,我得到的是空值。

我查看了在线上可用的大多数资源,但无法弄清楚我要去哪里。任何帮助表示赞赏。

非常感谢您的帮助。

spring spring-boot spring-batch batch-processing spring-framework-beans
1个回答
0
投票

在步骤1的项目编写器中,您正在执行:

ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("personDtoObject", responseList);

这意味着您将覆盖每个块的先前列表。您需要做的是从执行上下文中获取列表,并在覆盖键之前添加项目。您还需要在步骤边界(也就是第一个块和最后一个块)处添加一些健全性检查,以确保在将其放入执行上下文之前(尤其是最后一个块)将列表初始化并且该列表不是null )。

© www.soinside.com 2019 - 2024. All rights reserved.