spring-batch - job - spring batch maven
Almacenar en JobExecutionContext desde tasklet y acceder a otro tasklet (2)
Tengo un requisito en el cual un tasklet, almacena todos los archivos en los directorios en un arraylist. El tamaño de la lista se almacena en el contexto de ejecución del trabajo. Posteriormente se accede a este recuento desde otro tasklet en otro paso. ¿Cómo hacerlo? Traté de almacenar en el contexto de ejecución del trabajo, en el tiempo de ejecución arroja una excepción de colección no modificable,
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);
También almacené la referencia de la sección de pasos en la anotación beforestep. Todavía no es posible. De manera interesante, hágamelo saber, cómo compartir datos entre dos tasklets.
Otra forma es usar StepExecutionListener
que se llama después de la ejecución del paso. Tu tasklet puede implementarlo y compartir atributos locales.
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;
}
}
Entonces, en el paso, tu bean es un tasklet y un oyente como bramido. También debe configurar el alcance de su paso a "paso":
<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">
Tienes al menos 4 posibilidades:
- use el ExecutionPromotionListener para pasar datos a pasos futuros
- use un bean (spring) para mantener datos entre pasos, por ejemplo, un ConcurrentHashMap
- sin más acción, estos datos no serán accesibles para un reinicio
- El acceso a JobExecutionContext en su tasklet, debe usarse con precaución, causará problemas en el hilo de los pasos paralelos
- utilizar el nuevo jobscope (introducido con el lote de primavera 3)
Ejemplo de código para acceder a JobExecution desde Tasklet:
establecer un valor
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; } }
extrayendo un valor
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; } }
Creé ejemplos de código para las primeras 3 soluciones en mi repositorio de github de ejemplos de lotes de primavera , vea el complejo de módulos y el paquete interstepcomunicación