Item processing
ItemReader 和 ItemWriter 接口在各自的任务中非常有用,但如果你想在写入前插入业务逻辑呢?两种读取和写入的一种选择是使用复合模式:创建一个ItemWriter包含 另一个ItemWriter或ItemReader包含另一个ItemReader. 以下代码展示了一个示例:
public class CompositeItemWriter<T> implements ItemWriter<T> {
ItemWriter<T> itemWriter;
public CompositeItemWriter(ItemWriter<T> itemWriter) {
this.itemWriter = itemWriter;
}
public void write(Chunk<? extends T> items) throws Exception {
//Add business logic here
itemWriter.write(items);
}
public void setDelegate(ItemWriter<T> itemWriter){
this.itemWriter = itemWriter;
}
}
前一类包含另一个ItemWriter它在提供了一些业务逻辑后,将其委派给该模式可以轻松地用于ItemReader如 嗯,也许是为了获得更多基于所提供的输入的参考数据 主要ItemReader. 如果你需要控制呼叫,它也很有用写你自己。 然而,如果你只是想在提交给写作的项目真正写成之前“转换”它,你就不必写你自己。 你只需修改该项目即可。对于这个场景,Spring Batch 提供了ItemProcessor接口,如下所示接口定义显示:
public interface ItemProcessor<I, O> {
O process(I item) throws Exception;
}
一ItemProcessor很简单。给定一个对象,变换它并返回另一个对象。 这 前提是对象可能属于同一类型,也可能不同。关键是业务逻辑可以应用于进程中,而开发者完全需要自己去创建 逻辑。 一ItemProcessor可以直接接入一个步。例如,假设ItemReader提供了一类 类型福并且需要转换为类型酒吧在被写出之前。以下示例展示了一个ItemProcessor那个表演
转换:
public class Foo {}
public class Bar {
public Bar(Foo foo) {}
}
public class FooProcessor implements ItemProcessor<Foo, Bar> {
public Bar process(Foo foo) throws Exception {
//Perform simple transformation, convert a Foo to a Bar
return new Bar(foo);
}
}
public class BarWriter implements ItemWriter<Bar> {
public void write(Chunk<? extends Bar> bars) throws Exception {
//write bars
}
}
在前面的例子中,有一个名为 的类福,一个名为酒吧,以及一个类
叫Foo处理器这符合ItemProcessor接口。变换为
简单,但任何类型的变形都可以在这里完成。这律师写手写酒吧如果提供了其他类型,则抛出异常。同样,Foo处理器如果不是福提供。这Foo处理器然后可以注入到步,如下示例所示:
-
Java
-
XML
@Bean
public Job ioSampleJob(JobRepository jobRepository, Step step1) {
return new JobBuilder("ioSampleJob", jobRepository)
.start(step1)
.build();
}
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.<Foo, Bar>chunk(2).transactionManager(transactionManager)
.reader(fooReader())
.processor(fooProcessor())
.writer(barWriter())
.build();
}
<job id="ioSampleJob">
<step name="step1">
<tasklet>
<chunk reader="fooReader" processor="fooProcessor" writer="barWriter"
commit-interval="2"/>
</tasklet>
</step>
</job>
区别ItemProcessor和ItemReader或ItemWriter那是ItemProcessor对于 是可选的步.
链化ItemProcessor
在很多场景下,只做一次变换很有用,但如果你想做呢
“链式”组合多个ItemProcessor实现?你可以通过以下方式实现
就是前面提到的复合形态。更新之前的内容,单身
变换,示例,福被转换为酒吧,变换为福巴尔并写出,如下示例所示:
public class Foo {}
public class Bar {
public Bar(Foo foo) {}
}
public class Foobar {
public Foobar(Bar bar) {}
}
public class FooProcessor implements ItemProcessor<Foo, Bar> {
public Bar process(Foo foo) throws Exception {
//Perform simple transformation, convert a Foo to a Bar
return new Bar(foo);
}
}
public class BarProcessor implements ItemProcessor<Bar, Foobar> {
public Foobar process(Bar bar) throws Exception {
return new Foobar(bar);
}
}
public class FoobarWriter implements ItemWriter<Foobar>{
public void write(Chunk<? extends Foobar> items) throws Exception {
//write items
}
}
一个Foo处理器以及一个条形处理器可以“串联”起来得到福巴尔如下例所示:
CompositeItemProcessor<Foo,Foobar> compositeProcessor =
new CompositeItemProcessor<Foo,Foobar>();
List itemProcessors = new ArrayList();
itemProcessors.add(new FooProcessor());
itemProcessors.add(new BarProcessor());
compositeProcessor.setDelegates(itemProcessors);
就像前面的例子一样,你可以将复合处理器配置为步:
-
Java
-
XML
@Bean
public Job ioSampleJob(JobRepository jobRepository, Step step1) {
return new JobBuilder("ioSampleJob", jobRepository)
.start(step1)
.build();
}
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.<Foo, Foobar>chunk(2).transactionManager(transactionManager)
.reader(fooReader())
.processor(compositeProcessor())
.writer(foobarWriter())
.build();
}
@Bean
public CompositeItemProcessor compositeProcessor() {
List<ItemProcessor> delegates = new ArrayList<>(2);
delegates.add(new FooProcessor());
delegates.add(new BarProcessor());
CompositeItemProcessor processor = new CompositeItemProcessor();
processor.setDelegates(delegates);
return processor;
}
<job id="ioSampleJob">
<step name="step1">
<tasklet>
<chunk reader="fooReader" processor="compositeItemProcessor" writer="foobarWriter"
commit-interval="2"/>
</tasklet>
</step>
</job>
<bean id="compositeItemProcessor"
class="org.springframework.batch.infrastructure.item.support.CompositeItemProcessor">
<property name="delegates">
<list>
<bean class="..FooProcessor" />
<bean class="..BarProcessor" />
</list>
</property>
</bean>
过滤记录
项目处理器的一个典型用途是在记录传递前过滤掉它们
这ItemWriter.过滤是与跳过不同的动作。跳过表示
记录无效,而过滤表示记录不应无效
写。
例如,考虑一个批处理作业,读取包含三种不同类型
记录:需要插入的记录、需要更新的记录和需要删除的记录。如果记录删除
系统不支持,我们不希望发送任何可删除的记录到
这ItemWriter.然而,既然这些唱片其实并不算坏,我们也希望
过滤掉它们,而不是跳过它们。因此,ItemWriter只会收到
可插入且可更新的记录。
要筛选记录,你可以返回零来自ItemProcessor.该框架检测
结果为零并且避免将该项添加到交付记录列表中
这ItemWriter.一个例外,来自ItemProcessor结果为
跳。
验证输入
ItemReaders 和 ItemWriters 章节讨论了多种解析输入的方法。
每个主要实现如果不是“良好”都会抛出例外。这固定长度标记器如果缺少某一数据范围,会抛出异常。同样地
尝试访问索引行图仪或FieldSetMapper不存在或
格式与预期不同会导致抛出异常。全部
这类例外会被抛在前面读返回。然而,他们并未涉及相关内容
归还物品是否有效的问题。例如,如果
是年龄,不可能是负的。它之所以能正确解析,是因为它存在且
是一个数字,但它不会导致异常。因为已经有大量
Spring Batch 并不试图提供另一种验证框架。而是
提供一个简单的接口,称为验证器,你可以用任意数量的 实现
框架,正如以下接口定义所示:
public interface Validator<T> {
void validate(T value) throws ValidationException;
}
合同内容是驗證如果对象无效,方法会抛出异常
如果有效,则正常返回。Spring Batch提供了验证项目处理器,正如以下Beans定义所示:
-
Java
-
XML
@Bean
public ValidatingItemProcessor itemProcessor() {
ValidatingItemProcessor processor = new ValidatingItemProcessor();
processor.setValidator(validator());
return processor;
}
@Bean
public SpringValidator validator() {
SpringValidator validator = new SpringValidator();
validator.setValidator(new TradeValidator());
return validator;
}
<bean class="org.springframework.batch.infrastructure.item.validator.ValidatingItemProcessor">
<property name="validator" ref="validator" />
</bean>
<bean id="validator" class="org.springframework.batch.infrastructure.item.validator.SpringValidator">
<property name="validator">
<bean class="org.springframework.batch.samples.domain.trade.internal.validator.TradeValidator"/>
</property>
</bean>
你也可以使用BeanValidatingItemProcessor用于验证注释为
Bean 验证 API(JSR-303)注释。例如,考虑以下类型人:
class Person {
@NotEmpty
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
你可以通过声明BeanValidatingItemProcessor豆子在你的
应用上下文,并将其注册为针对区块的步骤中的处理器:
@Bean
public BeanValidatingItemProcessor<Person> beanValidatingItemProcessor() throws Exception {
BeanValidatingItemProcessor<Person> beanValidatingItemProcessor = new BeanValidatingItemProcessor<>();
beanValidatingItemProcessor.setFilter(true);
return beanValidatingItemProcessor;
}
容错
当一个区块被回滚时,读取过程中被缓存的项目可能会被
再加工。如果某一步配置为容错(通常通过使用跳跃或
重试处理),任意ItemProcessor被使用后应以以下方式实现
幂等。通常这包括对 的输入项不做任何更改
这ItemProcessor并且仅更新
这就是结果。