Как обрабатывать stateful item reader в SpringBatch

Наша работа SpringBatch имеет один шаг с помощью ItemReader, ItemProcessor и ItemWriter. Мы выполняем одно и то же задание одновременно с различными параметрами. ItemReader является stateful, поскольку он содержит входной поток, из которого он читает.

Таким образом, мы не хотим, чтобы один и тот же экземпляр ItemReader использовался для каждого вызова JobInstance (Job + Parameters).

Я не совсем уверен, какой из них является лучшим «охватом» для этой ситуации.

1) Должен ли шаг быть аннотирован @JobScope и ItemReader быть прототипом?

ИЛИ

2) должен ли шаг быть аннотирован @StepScope и ItemReader быть прототипом?

ИЛИ

3) Должен ли и шаг, и ItemReader быть аннотированы как прототип?

Конечный результат должен быть таким, чтобы новый ItemReader создавался для каждого нового выполнения задания с различными идентифицирующими параметрами (т. е. для каждого нового JobInstance).

Спасибо.
-АР_

2 ответа

  1. Вот как это происходит с точки зрения создания экземпляра класса (от минимум до большинства экземпляров):

    • Синглтон (на СПМ)
    • JobScope (за работу)
    • StepScope (за шаг)
    • Прототип (по ссылке)

    Если в одной JVM выполняется несколько заданий (при условии, что вы не находитесь в секционированном шаге, jobscope будет достаточно. Если у вас есть разделенный шаг, вам понадобится StepScope. Прототип был бы излишним во всех сценариях.

    Однако, если эти задания запускаются в разных JVM (а не в секционированном шаге), то простой одноэлементный боб будет просто прекрасным.

  2. Нет необходимости, чтобы каждый компонент (Step, ItemReader, ItemProcessor, ItemWriter) должен быть компонентом spring. Например, с SpringBatch-JavaApi только ваша работа должна быть SpringBean, но не ваши шаги, читатели и писатели:

        @Autowired
    private JobBuilderFactory jobs;
    
    @Autowired
    private StepBuilderFactory steps;
    
    @Bean
    public Job job() throws Exception {
        return this.jobs.get(JOB_NAME) // create jobbuilder
                .start(step1()) // add step 1
                .next(step2()) // add step 2
                .build(); // create job
    }
    
    @Bean
    public Job job() throws Exception {
        return this.jobs.get(JOB_NAME) // create jobbuilder
                .start(step1(JOB_NAME)) // add step 1
                .next(step2(JOB_NAME)) // add step 2
                .build(); // create job
    }
    
    private Step step1(String jobName) throws Exception {
    
        return steps.get(jobName + "_Step_1").chunk(10) //
                .faultTolerant() //
                .reader(() -> null) // you could lambdas
                .writer(items -> {
                }) //
                .build();
    }
    
    private Step step2(String jobName) throws Exception {
        return steps.get(jobName + "_Step_2").chunk(10) //
                .faultTolerant() //
                .reader(createDbItemReader(ds, sqlString, rowmapper)) //
                .writer(createFileWriter(resource, aggregator)) //
                .build();
    }
    

    Единственное, на что вы должны обратить внимание, это то, что вы должны вызвать «afterPropertiesSet» — методы при создании экземпляров, таких как JdbcCurserItemReader, FlatFileItemReader/Writer:

        private static <T> ItemReader<T> createDbItemReader(DataSource ds, String sql, RowMapper<T> rowMapper) throws Exception {
        JdbcCursorItemReader<T> reader = new JdbcCursorItemReader<>();
    
        reader.setDataSource(ds);
        reader.setSql(sql);
        reader.setRowMapper(rowMapper);
    
        reader.afterPropertiesSet(); // don't forget
        return reader;
    }
    
    private static <T> ItemWriter<T> createFileWriter(Resource target, LineAggregator<T> aggregator) throws Exception {
        FlatFileItemWriter<T> writer = new FlatFileItemWriter();
    
        writer.setEncoding("UTF-8");
        writer.setResource(target);
        writer.setLineAggregator(aggregator);
    
        writer.afterPropertiesSet(); // don't forget
        return writer;
    }
    

    Таким образом, вам не нужно возиться с областями. Каждая работа будет иметь свои собственные примеры своих шагов и своих читателей и писателей.

    Еще одним преимуществом этого подхода является то, что теперь вы можете создавать свои задания полностью динамически.