我正在编写一个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");
}
}
上述代码有效,但我发现有些边缘情况允许每Account
个NewsletterSubscriber
个Account
。所以我需要删除状态检查并将多个ItemProcessor
传递给项目编写者。
我找到的一个解决方案是更改ItemWriter
和List<Account>
来处理Account
类型而不是Account
,但这有两个缺点:
FaultTolerantChunkProcessor
对象可能会写在同一个交易中,因为给作者的列表可能包含多个帐户,我想避免这样做。有没有办法,可能使用监听器,或者更换spring批处理使用的一些内部组件以避免处理器中的列表?
我已经为这个问题打开了an issue on spring Jira。
我正在调查{{1}}中标有isComplete中的扩展点的getAdjustedOutputs和SimpleChunkProcessor
方法,看看我是否可以某种方式使用它们实现我的目标。
欢迎任何提示。
答案 0 :(得分:8)
项目处理器接受一件事,并返回一个列表
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);
}
}
}
答案 1 :(得分:3)
没有办法在每次调用时向Spring Batch中的ItemProcessor
返回多个项目,而不会深入杂草。如果您真的想知道ItemProcessor
和ItemWriter
退出之间的关系(不推荐),请查看ChunkProcessor
界面的实现。虽然简单的情况(SimpleChunkProcessor
)并没有那么糟糕,但是如果你使用任何容错逻辑(通过FaultTolerantChunkProcessor
跳过/重试),它就会变得非常笨拙。
一个更简单的选择是将此逻辑移动到ItemReader
,在返回项目之前进行此丰富。在返回项目之前,在执行服务查找的自定义ItemReader
实现中包装您正在使用的ItemReader
。在这种情况下,您不会从阅读器返回NewsletterSubscriber
,而是根据之前的信息返回Account
。
答案 2 :(得分:1)
而不是返回您返回的帐户,而不是创建AccountWrapper或Collection。作家显然必须考虑到这一点:)
答案 3 :(得分:0)
您可以制作转换器将Pojo(文件中的Pojo对象)转换为实体 通过编写以下代码:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>maa</groupId>
<artifactId>FlickerURLMaker</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>maa.flickerurlmaker.URLMaker</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
在您的商品处理器中
public class Intializer {
public static LGInfo initializeEntity() throws Exception {
Constructor<LGInfo> constr1 = LGInfo.class.getConstructor();
LGInfo info = constr1.newInstance();
return info;
}
}