从弹簧批次项目处理器返回多个项目

我正在编写一个弹簧批处理作业,在我的一个步骤中,我有处理器的以下代码:

@Component
public class SubscriberProcessor implements ItemProcessor<NewsletterSubscriber, Account>, InitializingBean {

    @Autowired
    private AccountService service;

    @Override public Account process(NewsletterSubscriber item) throws Exception {
        if (!Strings.isNullOrEmpty(item.getId())) {
            return service.getAccount(item.getId());
        }
        // search with email address
        List<Account> accounts = service.findByEmail(item.getEmail());
        checkState(accounts.size() <= 1, "Found more than one account with email %s", item.getEmail());
        return accounts.isEmpty() ? null : accounts.get(0);
    }

    @Override public void afterPropertiesSet() throws Exception {
        Assert.notNull(service, "account service must be set");
    }
}

上面的代码有效,但我发现在某些边缘情况下,允许每个代码具有多个代码。因此,我需要删除状态检查并将多个检查传递给项目编写器。AccountNewsletterSubscriberAccount

我发现的一个解决方案是改变两者并处理类型而不是类型,但这有两个缺点:ItemProcessorItemWriterList<Account>Account

  • 代码和测试更丑陋,更难编写和维护,因为编写器中有嵌套列表
  • 最重要的是,在同一事务中可以写入多个对象,因为提供给编写器的列表可能包含多个帐户,我想避免这种情况。Account

有没有办法,也许使用侦听器,或者替换spring批处理使用的一些内部组件,以避免处理器中的列表?

更新

我已经在春季Jira上为这个问题打开了一个问题。

我正在研究 isCompletegetAdjustedOutputs 方法,这些方法在 SimpleChunkProcessor 中被标记为扩展点,看看我是否能以某种方式使用它们来实现我的目标。FaultTolerantChunkProcessor

欢迎任何提示。


答案 1

项目处理器接收一个内容,并返回一个列表

MyItemProcessor implements ItemProcessor<SingleThing,List<ExtractedThingFromSingleThing>> {
    public List<ExtractedThingFromSingleThing> process(SingleThing thing) {
    //parse and convert to list
    }
}

包装下游编写器以解决问题。这样,本文作者下游的内容就不必使用列表。

@StepScope
public class ItemListWriter<T> implements ItemWriter<List<T>> {
    private ItemWriter<T> wrapped;

    public ItemListWriter(ItemWriter<T> wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public void write(List<? extends List<T>> items) throws Exception {
        for (List<T> subList : items) {
            wrapped.write(subList);
        }
    }
}

答案 2

没有办法在每次调用中将多个项目返回到春季批处理中,而不会深入杂草中。如果您真的想知道 和 之间的关系退出的位置(不推荐),请查看接口的实现。虽然简单的情况()并不是那么糟糕,但如果你使用任何容错逻辑(跳过/重试通过),它会变得非常快。ItemProcessorItemProcessorItemWriterChunkProcessorSimpleChunkProcessorFaultTolerantChunkProcessor

一个更简单的选项是在返回项目之前将此逻辑移动到执行此扩充的 。将您正在使用的任何内容包装在自定义实现中,该实现在返回项之前执行服务查找。在这种情况下,您不是从读者处返回 a,而是根据以前的信息返回 a。ItemReaderItemReaderItemReaderNewsletterSubscriberAccount


推荐