Передача данных на будущие этапы - Spring Batch - PullRequest
0 голосов
/ 11 сентября 2018

Как мы видим в Spring batch, официальная документация «Передача данных в будущие шаги - Spring Batch» возможна, но большинство из нас боролись с этим, потому что в официальной документации они упомянули две возможности. Уровень шага и один на уровне Задание .Проблема заключается в том, как получить данные на уровне шага?

Мое решение было таким же, как и в официальной документации, но оно не работало.Поэтому я решил сделать следующее:

1- Создать компонент для слушателя повышения:

<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);
}

Вы видите, в моем случае я сохраняю данные на карте (ConcurrentHashMap).

4 - ВАЖНО: На следующем шаге вы хотитечтобы получить данные, которые мы сохранили в предыдущем шаге.В этом порядке мы должны сделать:

  • Объявить объект, который будет содержать значение, которое мы получим, как:

    private Map fieldsMap;

Обратите внимание на JobExecution

enter image description here

@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 на той же работе.Они имеют одинаковое выполнение работы.Теперь взгляните на изображение моего режима отладки.

Подскажите, пожалуйста, если есть другой способ.

ПРИМЕЧАНИЕ: Пожалуйста, не просто копируйте и вставляйте код из официальной документации, предоставьте свой собственный.ответ или реализация.

Ссылка на документацию на пружинную партию, относящуюся к этой проблеме, находится ниже введите описание ссылки здесь

1 Ответ

0 голосов
/ 11 сентября 2018

Вы путаете ключи, которые должны быть переведены из контекста выполнения шага в контекст выполнения задания с самими данными.Эта путаница происходит из двух мест:

  • <beans:property name="keys" value="someValues"/>: someValues должно быть someKeys
  • , вызывая executionContext.put("keys", someValues); в @BeforeStep неверно

Позвольте мне сделать это немного яснее.Представьте, что у вас есть задание с двумя шагами:

  • шаг 1: чтение / запись некоторых элементов и запись количества элементов в контексте выполнения шага
  • шаг 2: необходим доступ к элементупосчитайте и распечатайте его на консоли.

В этом случае вы можете использовать прослушиватель повышения, чтобы преобразовать «счет» ключа из контекста выполнения шага 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

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...