Spring Batch : 在不同steps间传递数据

参考文档:

How can we share data between the different steps of a Job in Spring Batch?

Job Scoped Beans in Spring Batch

https://github.com/spring-projects/spring-batch/issues/1335

有三种方式:

  1. Use StepContext and promote it to JobContext and you have access to it from each step, you must as noted obey limit in size
  2. Create @JobScope bean and add data to that bean, @Autowire it where needed and use it (drawback is that it is in-memory structure and if job fails data is lost, migh cause problems with restartability)
  3. We had larger datasets needed to be processed across steps (read each line in csv and write to DB, read from DB, aggregate and send to API) so we decided to model data in new table in same DB as spring batch meta tables, keep ids in JobContext and access when needed and delete that temporary table when job finishes successfully.

1|0使用 JobContext

通过step_execution 或者 job_execution来在不同step中传递数据。

但是如果数据量大的话,这将不是一种好的方式.因为spring batch默认会通过job repository将 step_executionjob_execution进行持久化.

Use ExecutionContextPromotionListener:

首先在第一个Step中放到StepExecution

public class YourItemWriter implements ItemWriter<Object> { private StepExecution stepExecution; public void write(List<? extends Object> items) throws Exception { // Some Business Logic // put your data into stepexecution context ExecutionContext stepContext = this.stepExecution.getExecutionContext(); stepContext.put("someKey", someObject); } @BeforeStep public void saveStepExecution(Final StepExecution stepExecution) { this.stepExecution = stepExecution; } }

然后使用promotionListener在监听器中将其升级到JobExecution中:

@Bean public Step step1() { return stepBuilder .get("step1")<Company,Company> chunk(10) .reader(reader()).processor(processor()).writer(writer()) .listener(promotionListener()).build(); } @Bean public ExecutionContextPromotionListener promotionListener() { ExecutionContextPromotionListener listener = new ExecutionContextPromotionListener(); listener.setKeys(new String[] {"someKey"}); listener.setStrict(true); return listener; }

在第二个Step中使用ExecutionContext获取:

public class RetrievingItemWriter implements ItemWriter<Object> { private Object someObject; public void write(List<? extends Object> items) throws Exception { // ... } @BeforeStep public void retrieveInterstepData(StepExecution stepExecution) { JobExecution jobExecution = stepExecution.getJobExecution(); ExecutionContext jobContext = jobExecution.getExecutionContext(); this.someObject = jobContext.get("someKey"); } }

如果你使用的是tasklets的话,可以这样获取:

List<YourObject> yourObjects = (List<YourObject>) chunkContent.getStepContext().getJobExecutionContext().get("someKey");

2|0用自己定义的bean传递数据

创建一个data holder

@Component @JobScope public class PublicCompanyHolder { private List<PublicCompanyInfo> publicCompanyList; public List<PublicCompanyInfo> getPublicCompanyList() { return publicCompanyList; } public void setPublicCompanyList(List<PublicCompanyInfo> publicCompanyList) { this.publicCompanyList = publicCompanyList; } }

在step 1中设置数据:

@Component("pubTasklet") public class PubTasklet implements Tasklet { @Autowired private PublicCompanyHolder publicCompanyHolder; public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { List<PublicCompanyInfo> infoContainer = new ArrayList<PublicCompanyInfo>(); for (int i=0; i < 10; i++) { PublicCompanyInfo info = new PublicCompanyInfo(); info.setPublicCompanyId("ID-" + i); info.setPublicCompanyName("Name*" + i); infoContainer.add(info); } publicCompanyHolder.setPublicCompanyList(infoContainer); return RepeatStatus.FINISHED; } }

在step2中取数据:

@Component("pubTasklet2") public class PubTasklet2 implements Tasklet { @Autowired private PublicCompanyHolder publicCompanyHolder; public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("received holder:" + publicCompanyHolder.getPublicCompanyList()); return RepeatStatus.FINISHED; } }

job配置

  • define.xml
<job id="pubJob" restartable="true"> <step id="step1" next="step2"> <tasklet ref="pubTasklet" /> </step> <step id="step2" next="step1"> // if you do not want to loop, remove next <tasklet ref="pubTasklet2" /> </step> <listeners> <listener ref="pubListener" /> </listeners> </job>
  • Job Config
public Job build(Step step1, Step step2) { return jobBuilderFactory.get("jobName") .incrementer(new RunIdIncrementer()) .start(step1) .next(step2) .build(); } public Step step1() { return stepBuilderFactory.get("step1Name") .tasklet(new PubTasklet()) .build(); } public Step step2() { return stepBuilderFactory.get("step2Name") .tasklet(new PubTasklet2()) .build(); }

__EOF__

本文作者咫尺是梦
本文链接https://www.cnblogs.com/satire/p/15471611.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   satire  阅读(2843)  评论(4编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示