我们可以在Spring批处理正式文档中看到“将数据传递到将来的步骤-Spring Batch”是可能的,但是我们大多数人都在为此苦苦挣扎,因为他们在正式文档中提到了两种可能性。 步骤级别和一个工作级别。问题是如何在步骤级别检索数据?
我的解决方案与官方文档中的解决方案相同,但是没有用。因此,我决定执行以下操作:
1-创建用于升级侦听器的bean:
<beans:bean id="promotionListener"
class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">
<beans:property name="keys" value="someValues"/>
</beans:bean>
2-在您的步骤中设置侦听器(您要保存数据的步骤)
<listeners>
<listener ref="promotionListener"/>
</listeners>
3-在编写器的同一步骤(保存数据的步骤)中,保存数据。
private StepExecution stepExecution;
@BeforeStep
public void saveStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
ExecutionContext executionContext = stepExecution.getExecutionContext();
Map<String, String> fieldsMap= new HashMap<>();
executionContext.put("keys", someValues);
}
@Override
public void write(List<? extends Map<String, String>> items) throws Exception {
LOGGER.info(items.toString());
Map<String, String> fieldsMap= new ConcurrentHashMap<>();
items.forEach(item -> item.forEach(fieldsMap::put));
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
stepContext.put("keys", fieldsMap);
}
对于我来说,您可以看到我正在将数据保存在Map(ConcurrentHashMap)中。
4-重要信息:在下一步中,您要检索上一步中保存的数据。按照该顺序,我们必须执行以下操作:
声明将包含我们将检索为的值的对象:
私人地图栏位地图;
请注意 JobExecution
@BeforeStep
public void retrieveInterStepData(StepExecution stepExecution) {
JobExecution jobExecution = stepExecution.getJobExecution();
Collection<StepExecution> stepExecutions = jobExecution.getStepExecutions();
for (StepExecution steps : stepExecutions) {
ExecutionContext executionContext = steps.getExecutionContext();
if (executionContext.containsKey("keys")) {
this.nationalityMap = (Map<String, String>) executionContext.get("keys");
}
}
}
就是这样! 您可能想知道为什么我不遵循官方文档中的说明?原因是我在同一工作中与Steps一起工作。他们共享相同的工作执行。现在看看我的调试模式。
如果还有其他建议,请提出建议。
注意:请不要仅从正式文档中复制和粘贴代码,也不提供您自己的答案或实现。
与该问题相关的spring batch文档的链接如下 enter link description here
答案 0 :(得分:1)
您在混淆将要从步骤执行上下文提升到作业执行上下文的键与数据本身。这种混乱来自两个地方:
<beans:property name="keys" value="someValues"/>
:someValues
应该是someKeys
executionContext.put("keys", someValues);
中调用@BeforeStep
是不正确的让我更清楚一点。想象一下您有两个步骤的工作:
在这种情况下,您可以使用提升侦听器将键“ count”从步骤1的步骤执行上下文提升到作业执行上下文,以便步骤2可以访问它。这是一个示例:
import java.util.Arrays;
import java.util.List;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
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.core.launch.JobLauncher;
import org.springframework.batch.core.listener.ExecutionContextPromotionListener;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class MyJob {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
public ItemReader<Integer> itemReader() {
return new ListItemReader<>(Arrays.asList(1, 2, 3, 4));
}
@Bean
public ItemWriter<Integer> itemWriter() {
return new ItemWriter<Integer>() {
private StepExecution stepExecution;
@Override
public void write(List<? extends Integer> items) {
for (Integer item : items) {
System.out.println("item = " + item);
}
ExecutionContext stepContext = this.stepExecution.getExecutionContext();
int count = stepContext.containsKey("count") ? stepContext.getInt("count") : 0;
stepContext.put("count", count + items.size());
}
@BeforeStep
public void saveStepExecution(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
};
}
@Bean
public Step step1() {
return steps.get("step1")
.<Integer, Integer>chunk(2)
.reader(itemReader())
.writer(itemWriter())
.listener(promotionListener())
.build();
}
@Bean
public Step step2() {
return steps.get("step2")
.tasklet((contribution, chunkContext) -> {
// retrieve the key from the job execution context
Integer count = (Integer) chunkContext.getStepContext().getJobExecutionContext().get("count");
System.out.println("In step 2: step 1 wrote " + count + " items");
return RepeatStatus.FINISHED;
})
.build();
}
@Bean
public ExecutionContextPromotionListener promotionListener() {
ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener();
listener.setKeys(new String[] {"count"});
return listener;
}
@Bean
public Job job() {
return jobs.get("job")
.start(step1())
.next(step2())
.build();
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
}
此打印:
item = 1
item = 2
item = 3
item = 4
In step 2: step 1 wrote 4 items
希望这会有所帮助。