Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
360 views
in Technique[技术] by (71.8m points)

Multiple writers for different types in the same Spring Batch step

I am writing a Spring Batch application with the following workflow:

  1. Read some items of type A (using a FlatFileItemReader<A>).
  2. Process an item, transforming it from A to B.
  3. Write the processed items of type B (using a JdbcBatchItemWriter<B>)
  4. Eventually, I should call an external service (a RESTful API, but it could be a SimpleMailMessageItemWriter<A>) using data from the source type A.

How can I configure such a workflow?

So far, I have found the following workaround:

  • Configuring a CompositeItemWriter<B> which delegates to:
    1. The actual ItemWriter<B>
    2. A custom ItemWriter<B> implementation which converts B back to A and then writes an A

But this is a cumbersome solution because it forces me to either:

  • Duplicate processing logic: from A to B and back again.
  • Sneakily hide some attributes from the source object A inside B, polluting the domain model.

Note: since my custom item writer for A needs to invoke an external service, I would like to perform this operation after B has been successfully written.

Here are the relevant parts of the batch configuration code.

@Bean
public Step step(StepBuilderFactory steps, ItemReader<A> reader, ItemProcessor<A, B> processor, CompositeItemWriter<B> writer) {
    return steps.get("step")
            .<A, B>chunk(10)
            .reader(reader)
            .processor(processor)
            .writer(writer)
            .build();
}

@Bean
public CompositeItemWriter<B> writer(JdbcBatchItemWriter<B> jdbcBatchItemWriter, CustomItemWriter<B, A> customItemWriter) {
    return new CompositeItemWriterBuilder<B>()
            .delegates(jdbcBatchItemWriter, customItemWriter)
            .build();
}
question from:https://stackoverflow.com/questions/66045423/multiple-writers-for-different-types-in-the-same-spring-batch-step

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

For your use case, I would encapsulate A and B in a wrapper type, such AB:

class AB {
   private A originalItem;
   private B transformedItem;
}

With that, you would have: ItemReader<A>, ItemProcessor<A, AB> and ItemWriter<AB>. The processor creates instances of AB in which it keeps a reference to the original item. The writer can then get access to both types and delegate to the JdbcBatchItemReader<B> and SimpleMailMessageItemWriter<A> as needed, something like:

class ABItemWriter implements ItemWriter<AB> {
    private JdbcBatchItemWriter<B> jdbcBatchItemWriter;
    private SimpleMailMessageItemWriter mailMessageItemWriter;
    // constructor with delegates

    @Override
    public void write(List<? extends AB> items) throws Exception {
        jdbcBatchItemWriter.write(getBs(items));
        mailMessageItemWriter.write(getAs(items)); // this would not be called if the jdbc writer fails
    }
}

The methods getAs and getBs would extract items of type A/B from AB. Encapsulation for the win! BTW, a Java record is a good option for type AB.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...