Item processing
项目处理
ItemReader和ItemWriter接口对于其特定的
任务,但是如果您想在编写之前插入业务逻辑怎么办?两者一选一
读写就是使用复合模式:创建一个包含
another 或包含另一个 .以下内容
代码显示了一个例子: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(List<? extends T> items) throws Exception {
//Add business logic here
itemWriter.write(items);
}
public void setDelegate(ItemWriter<T> itemWriter){
this.itemWriter = itemWriter;
}
}
前面的类包含另一个类,它在具有
提供了一些业务逻辑。此模式可以很容易地用于 as
好吧,也许是为了根据
主要。如果您需要控制对自己的调用,它也很有用。
但是,如果您只想“转换”传入的项,以便在写入之前进行写入
其实写的,你不需要自己。您可以只修改项目。对于这个
场景中,Spring Batch 提供了相应的接口,如下所示
接口定义:ItemWriter
ItemReader
ItemReader
write
write
ItemProcessor
public interface ItemProcessor<I, O> {
O process(I item) throws Exception;
}
An 很简单。给定一个对象,转换它并返回另一个对象。这
提供的对象可能属于同一类型,也可能不是同一类型。关键是业务逻辑可以
在流程中应用,并且完全由开发人员来创建它
逻辑。An 可以直接连接到步骤中。例如,假设 an 提供了一个 type 类,并且需要在写出之前将其转换为 type。以下示例显示了执行
转换:ItemProcessor
ItemProcessor
ItemReader
Foo
Bar
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(List<? extends Bar> bars) throws Exception {
//write bars
}
}
在前面的示例中,有一个 class 、 class 和一个符合接口的 class。转换是
很简单,但任何类型的转换都可以在这里完成。写入对象,如果提供了任何其他类型,则引发异常。同样,如果提供了除 a 之外的任何内容,则 the 会引发异常。然后,可以将 注入到 中,如以下示例所示:Foo
Bar
FooProcessor
ItemProcessor
BarWriter
Bar
FooProcessor
Foo
FooProcessor
Step
<job id="ioSampleJob">
<step name="step1">
<tasklet>
<chunk reader="fooReader" processor="fooProcessor" writer="barWriter"
commit-interval="2"/>
</tasklet>
</step>
</job>
@Bean
public Job ioSampleJob() {
return this.jobBuilderFactory.get("ioSampleJob")
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<Foo, Bar>chunk(2)
.reader(fooReader())
.processor(fooProcessor())
.writer(barWriter())
.build();
}
和 or 之间的区别在于 an 对于 .ItemProcessor
ItemReader
ItemWriter
ItemProcessor
Step
链接 ItemProcessors
在许多情况下,执行单个转换都很有用,但如果您想
将多个实现“链接”在一起?这可以通过
前面提到的复合模式。要更新上一个
转换(例如)转换为 ,后者被转换为并写出,如以下示例所示:ItemProcessor
Foo
Bar
Foobar
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(List<? extends Foobar> items) throws Exception {
//write items
}
}
A 和 a 可以“链接”在一起以得到结果,如以下示例所示:FooProcessor
BarProcessor
Foobar
CompositeItemProcessor<Foo,Foobar> compositeProcessor =
new CompositeItemProcessor<Foo,Foobar>();
List itemProcessors = new ArrayList();
itemProcessors.add(new FooProcessor());
itemProcessors.add(new BarProcessor());
compositeProcessor.setDelegates(itemProcessors);
与前面的示例一样,复合处理器可以配置为 :Step
<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.item.support.CompositeItemProcessor">
<property name="delegates">
<list>
<bean class="..FooProcessor" />
<bean class="..BarProcessor" />
</list>
</property>
</bean>
@Bean
public Job ioSampleJob() {
return this.jobBuilderFactory.get("ioSampleJob")
.start(step1())
.build();
}
@Bean
public Step step1() {
return this.stepBuilderFactory.get("step1")
.<Foo, Foobar>chunk(2)
.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;
}
筛选记录
项目处理器的一个典型用途是在将记录传递给
这。筛选是一种不同于跳过的操作。跳过表示
记录无效,而筛选只是表示记录不应为
写。ItemWriter
例如,考虑一个批处理作业,它读取包含三种不同类型的
记录:要插入的记录、要更新的记录和要删除的记录。如果记录删除
,则我们不希望将任何 “delete” 记录发送到
这。但是,由于这些记录实际上并不是坏记录,因此我们希望
过滤掉它们而不是跳过它们。因此,将只接收
“insert” 和 “update” 记录。ItemWriter
ItemWriter
要筛选记录,您可以从 .框架检测
,并避免将该项目添加到传递到
这。像往常一样,从
跳。null
ItemProcessor
null
ItemWriter
ItemProcessor
验证输入
在 ItemReaders 和 ItemWriters 一章中,解析输入的多种方法
讨论。如果每个主要实现不是 “格式正确” ,则会引发异常。如果缺少数据范围,则引发异常。同样地
尝试访问不存在的 OR 中的索引,或者
的格式与预期的格式不同,会导致引发异常。全部
这些类型的异常在 return 之前引发。但是,它们没有解决
返回的项目是否有效的问题。例如,如果其中一个字段
是一个年龄,显然不能是负数。它可能会正确解析,因为它存在并且
是一个数字,但不会导致异常。由于已经有大量的
验证框架,Spring Batch 不会尝试提供另一个。相反,它
提供了一个简单的接口,称为 ,该接口可以由任意数量的
frameworks,如以下接口定义所示:FixedLengthTokenizer
RowMapper
FieldSetMapper
read
Validator
public interface Validator<T> {
void validate(T value) throws ValidationException;
}
协定是,如果对象无效,该方法将引发异常
如果有效,则正常返回。Spring Batch 提供了一个 out of the box ,如以下 bean 定义所示:validate
ValidatingItemProcessor
<bean class="org.springframework.batch.item.validator.ValidatingItemProcessor">
<property name="validator" ref="validator" />
</bean>
<bean id="validator" class="org.springframework.batch.item.validator.SpringValidator">
<property name="validator">
<bean class="org.springframework.batch.sample.domain.trade.internal.validator.TradeValidator"/>
</property>
</bean>
@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 验证 API (JSR-303) 注释。例如,给定以下 type :BeanValidatingItemProcessor
Person
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;
}
}
您可以通过在
application context 并在面向 chunk 的步骤中将其注册为处理器:BeanValidatingItemProcessor
@Bean
public BeanValidatingItemProcessor<Person> beanValidatingItemProcessor() throws Exception {
BeanValidatingItemProcessor<Person> beanValidatingItemProcessor = new BeanValidatingItemProcessor<>();
beanValidatingItemProcessor.setFilter(true);
return beanValidatingItemProcessor;
}