Java 从 Spring Batch ItemProcessor 返回多个项目
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24004959/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Return multiple items from spring batch ItemProcessor
提问by Fabio
I'm writing a spring batch job and in one of my step I have the following code for the processor:
我正在编写一个 spring 批处理作业,在我的步骤之一中,我为处理器编写了以下代码:
@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");
}
}
The above code works but I've found out that there are some edge cases where having more than one Account
per NewsletterSubscriber
is allowed. So I need to remove the state check and to pass more than one Account
to the item writer.
上面的代码有效,但我发现在某些边缘情况下,Account
每个NewsletterSubscriber
允许超过一个。所以我需要删除状态检查并将多个传递Account
给项目编写器。
One solution I found is to change both ItemProcessor
and ItemWriter
to deal with List<Account>
type instead of Account
but this have two drawbacks:
我发现的一种解决方案是同时更改ItemProcessor
并ItemWriter
处理List<Account>
类型而不是,Account
但这有两个缺点:
- Code and tests are uglier and harder to write and maintain because of nested lists in writer
- Most important more than one
Account
object may be written in the same transaction because a list given to writer may contain multiple accounts and I'd like to avoid this.
- 由于 writer 中的嵌套列表,代码和测试更难看,更难编写和维护
- 最重要的
Account
是,在同一个事务中可能会写入多个对象,因为提供给 writer 的列表可能包含多个帐户,我想避免这种情况。
Is there any way, maybe using a listener, or replacing some internal component used by spring batch to avoid lists in processor?
有什么办法,也许使用侦听器,或者替换 spring 批处理使用的一些内部组件来避免处理器中的列表?
Update
更新
I've opened an issue on spring Jirafor this problem.
我已经针对这个问题在 spring Jira 上打开了一个问题。
I'm looking into isCompleteand getAdjustedOutputsmethods in FaultTolerantChunkProcessor
which are marked as extension points in SimpleChunkProcessor
to see if I can use them in some way to achieve my goal.
我正在研究isComplete和getAdjustedOutputs方法,在FaultTolerantChunkProcessor
这些方法中被标记为扩展点,SimpleChunkProcessor
看看我是否可以以某种方式使用它们来实现我的目标。
Any hint is welcome.
欢迎任何提示。
回答by Michael Minella
There isn't a way to return more than one item per call to an ItemProcessor
in Spring Batch without getting pretty far into the weeds. If you really want to know where the relationship between an ItemProcessor
and ItemWriter
exits (not recommended), take a look at the implementations of the ChunkProcessor
interface. While the simple case (SimpleChunkProcessor
) isn't that bad, if you use any of the fault tolerant logic (skip/retry via FaultTolerantChunkProcessor
), it get's very unwieldily quick.
没有一种方法可以ItemProcessor
在不深入杂草的情况下每次调用返回一个以上的项目到Spring Batch 中。如果你真的想知道anItemProcessor
和ItemWriter
exit的关系在哪里(不推荐),看看ChunkProcessor
接口的实现。虽然简单的情况 ( SimpleChunkProcessor
) 并没有那么糟糕,但如果您使用任何容错逻辑(通过 跳过/重试FaultTolerantChunkProcessor
),它会变得非常笨拙。
A much simpler option would be to move this logic to an ItemReader
that does this enrichment before returning the item. Wrap whatever ItemReader
you're using in a custom ItemReader
implementation that does the service lookup before returning the item. In this case, instead of returning a NewsletterSubscriber
from the reader, you'd be returning an Account
based on the previous information.
一个更简单的选择是ItemReader
在返回项目之前将此逻辑移至执行此扩充的 。将ItemReader
您正在使用的任何内容包装在一个自定义ItemReader
实现中,该实现在返回项目之前执行服务查找。在这种情况下,不是NewsletterSubscriber
从读取器返回 a,而是Account
根据先前的信息返回 a 。
回答by Esben
Instead of returning an Account you return create an AccountWrapper or Collection. The Writer obviously must take this into account :)
您返回创建一个 AccountWrapper 或 Collection,而不是返回一个 Account。作家显然必须考虑到这一点:)
回答by Matt Broekhuis
Item Processor takes one thing in, and returns a list
项目处理器接收一件事,并返回一个列表
MyItemProcessor implements ItemProcessor<SingleThing,List<ExtractedThingFromSingleThing>> {
public List<ExtractedThingFromSingleThing> process(SingleThing thing) {
//parse and convert to list
}
}
Wrap the downstream writer to iron things out. This way stuff downstream from this writer doesn't have to work with lists.
包装下游作家以解决问题。这样,作者下游的东西就不必使用列表了。
@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);
}
}
}
回答by Salah Atwa
You can made transformer to transform your Pojo( Pojo object from file) to your Entity By making the following code :
您可以通过制作以下代码来制作转换器以将您的 Pojo(来自文件的 Pojo 对象)转换为您的实体:
public class Intializer {
public static LGInfo initializeEntity() throws Exception {
Constructor<LGInfo> constr1 = LGInfo.class.getConstructor();
LGInfo info = constr1.newInstance();
return info;
}
}
And in your item Processor
并在您的项目处理器中
public class LgItemProcessor<LgBulkLine, LGInfo> implements ItemProcessor<LgBulkLine, LGInfo> {
private static final Log log = LogFactory.getLog(LgItemProcessor.class);
@SuppressWarnings("unchecked")
@Override
public LGInfo process(LgBulkLine item) throws Exception {
log.info(item);
return (LGInfo) Intializer.initializeEntity();
}
}