spring 从 tasklet 中存储在 JobExecutionContext 中并在另一个 tasklet 中访问
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8117060/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Storing in JobExecutionContext from tasklet and accessing in another tasklet
提问by Dead Programmer
I have a requirement in which a tasklet, stores all the files in the directories in an arraylist. The size of the list is stored in the job execution context. Later this count is accessed from another tasklet in another step. How do it do this. I tried to store in jobexecution context, at runtime throws unmodifiable collection exception,
我有一个要求,其中一个 tasklet 将目录中的所有文件存储在一个数组列表中。列表的大小存储在作业执行上下文中。稍后在另一个步骤中从另一个 tasklet 访问此计数。这是怎么做到的。我试图存储在 jobexecution 上下文中,在运行时抛出不可修改的集合异常,
public RepeatStatus execute(StepContribution arg0, ChunkContext arg1)
throws Exception {
StepContext stepContext = arg1.getStepContext();
StepExecution stepExecution = stepContext.getStepExecution();
JobExecution jobExecution = stepExecution.getJobExecution();
ExecutionContext jobContext = jobExecution.getExecutionContext();
jobContext.put("FILE_COUNT",150000);
also stored the stepexection reference in beforestep annotation .still not possioble.kindly let me know ,how to share data between two tasklets.
还将 stepexection 引用存储在 beforestep 注释中。仍然不可能。请告诉我,如何在两个 tasklet 之间共享数据。
回答by Michael Pralow
you have at least 4 possibilities:
你至少有 4 种可能性:
- use the ExecutionPromotionListener to pass data to future steps
- use a (spring) bean to hold inter-step data, e.g. a ConcurrentHashMap
- without further action this data won't be accessible for a re-start
- access the JobExecutionContext in your tasklet, should be used with caution, will cause thread problems for parallel steps
- use the new jobscope(introduced with spring batch 3)
- 使用 ExecutionPromotionListener将数据传递给后续步骤
- 使用 (spring) bean 来保存步骤间数据,例如 ConcurrentHashMap
- 如果不采取进一步行动,将无法重新开始访问此数据
- 访问 tasklet 中的 JobExecutionContext,应谨慎使用,会导致并行步骤的线程问题
- 使用新的jobscope(引入的弹簧批次3)
Code Example for accessing JobExecution from Tasklet:
从 Tasklet 访问 JobExecution 的代码示例:
setting a value
public class ChangingJobExecutionContextTasklet implements Tasklet { /** {@inheritDoc} */ @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { // set variable in JobExecutionContext chunkContext .getStepContext() .getStepExecution() .getJobExecution() .getExecutionContext() .put("value", "foo"); // exit the step return RepeatStatus.FINISHED; } }extracting a value
public class ReadingJobExecutionContextTasklet implements Tasklet { private static final Logger LOG = LoggerFactory.getLogger(ChangingJobExecutionContextTasklet.class); /** {@inheritDoc} */ @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { // pull variable from JobExecutionContext String value = (String) chunkContext .getStepContext() .getStepExecution() .getJobExecution() .getExecutionContext() .get("value"); LOG.debug("Found value in JobExecutionContext:" + value); // exit the step return RepeatStatus.FINISHED; } }
设定值
public class ChangingJobExecutionContextTasklet implements Tasklet { /** {@inheritDoc} */ @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { // set variable in JobExecutionContext chunkContext .getStepContext() .getStepExecution() .getJobExecution() .getExecutionContext() .put("value", "foo"); // exit the step return RepeatStatus.FINISHED; } }提取值
public class ReadingJobExecutionContextTasklet implements Tasklet { private static final Logger LOG = LoggerFactory.getLogger(ChangingJobExecutionContextTasklet.class); /** {@inheritDoc} */ @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { // pull variable from JobExecutionContext String value = (String) chunkContext .getStepContext() .getStepExecution() .getJobExecution() .getExecutionContext() .get("value"); LOG.debug("Found value in JobExecutionContext:" + value); // exit the step return RepeatStatus.FINISHED; } }
i created code examples for the first 3 solutions in my spring-batch-examples github repository, see module complexand package interstepcommunication
我在我的 spring-batch-examples github 存储库中为前 3 个解决方案创建了代码示例,请参阅模块复杂和包interstepcommunication
回答by user1067920
Another way is to use StepExecutionListenerwhich is called after step execution.
Your tasklet can implements it and share local attribute.
另一种方法是使用StepExecutionListenerwhich 在步骤执行后调用。您的 tasklet 可以实现它并共享本地属性。
public class ReadingJobExecutionContextTasklet implements Tasklet, StepExecutionListener {
private String value;
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
ExecutionContext jobExecutionContext = stepExecution.getJobExecution().getExecutionContext();
jobExecutionContext.put("key", value);
//Return null to leave the old value unchanged.
return null;
}
}
So, in the step, your bean is a tasklet and a listener like bellow. You should also configure the scope of you step to "step" :
因此,在该步骤中,您的 bean 是一个 tasklet 和一个如下所示的侦听器。您还应该将 step 的范围配置为 "step" :
<batch:step id="myStep" next="importFileStep">
<batch:tasklet>
<ref bean="myTasklet"/>
<batch:listeners>
<batch:listener ref="myTasklet"/>
</batch:listeners>
</batch:tasklet>
</batch:step>
<bean id="myTasklet" class="ReadingJobExecutionContextTasklet" scope="step">

