项目处理
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
.如果您需要控制对write
你自己。
但是,如果您只想 “转换” 传入的项,以便在写入之前写入
实际编写,你不需要write
你自己。您可以只修改项目。对于这个
场景中,Spring Batch 提供了ItemProcessor
接口,如下所示
接口定义显示:
public interface ItemProcessor<I, O> {
O process(I item) throws Exception;
}
一ItemProcessor
很简单。给定一个对象,转换它并返回另一个对象。这
提供的对象可能属于同一类型,也可能不是同一类型。关键是业务逻辑可以
在流程中应用,并且完全由开发人员来创建它
逻辑。一ItemProcessor
可以直接连接到步骤中。例如,假设ItemReader
提供Foo
并且它需要转换为 typeBar
在被写出之前。以下示例显示了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
中,一个名为Bar
和一个类
叫FooProcessor
遵守ItemProcessor
接口。转换是
很简单,但任何类型的转换都可以在这里完成。这BarWriter
写Bar
对象,如果提供了任何其他类型,则引发异常。同样,FooProcessor
如果除Foo
。这FooProcessor
然后可以注入到Step
,如下例所示:
-
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)
.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
对于一个Step
.
链接 ItemProcessors
在许多情况下,执行单个转换都很有用,但如果您想
将多个ItemProcessor
实现?您可以通过使用
前面提到的复合模式。要更新上一个
transformation, 示例,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(Chunk<? extends Foobar> items) throws Exception {
//write items
}
}
一个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
:
-
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)
.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.item.support.CompositeItemProcessor">
<property name="delegates">
<list>
<bean class="..FooProcessor" />
<bean class="..BarProcessor" />
</list>
</property>
</bean>
筛选记录
项目处理器的一个典型用途是在将记录传递给
这ItemWriter
.筛选是一种不同于跳过的作。跳过表示
记录无效,而筛选表示记录不应无效
写。
例如,考虑一个批处理作业,它读取包含三种不同类型的
记录:要插入的记录、要更新的记录和要删除的记录。如果记录删除
不受系统支持,我们不希望将任何可删除的记录发送到
这ItemWriter
.但是,由于这些记录实际上并不是不良记录,因此我们希望
过滤掉它们而不是跳过它们。因此,ItemWriter
将只收到
可插入和可更新的记录。
要筛选记录,您可以返回null
从ItemProcessor
.框架检测
,结果是null
并避免将该项目添加到传送到
这ItemWriter
.从ItemProcessor
结果为
跳。
验证输入
ItemReaders和ItemWriters一章讨论了解析 Importing 的多种方法。
如果每个主要实现不是 “格式正确” ,则会引发异常。这FixedLengthTokenizer
如果缺少 data 范围,则引发异常。同样地
尝试访问RowMapper
或FieldSetMapper
不存在或
的格式与预期的格式不同,会导致引发异常。全部
这些类型的异常是在read
返回。但是,它们没有解决
返回的项目是否有效的问题。例如,如果其中一个字段
是一个年龄,它不能是负数。它可能会正确解析,因为它存在并且
是一个数字,但不会导致异常。由于已经有大量的
验证框架,Spring Batch 不会尝试提供另一个。相反,它
提供了一个简单的接口,称为Validator
,您可以通过任意数量的
frameworks,如下面的接口定义所示:
public interface Validator<T> {
void validate(T value) throws ValidationException;
}
合同是validate
method 如果对象无效,则引发异常
如果有效,则正常返回。Spring Batch 提供了一个ValidatingItemProcessor
,如下面的 bean 定义所示:
-
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.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.samples.domain.trade.internal.validator.TradeValidator"/>
</property>
</bean>
您还可以使用BeanValidatingItemProcessor
验证 注释 的项目
Bean 验证 API (JSR-303) 注释。例如,请考虑以下类型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;
}
}
您可以通过声明BeanValidatingItemProcessor
bean 中的
application context 并在面向 chunk 的步骤中将其注册为处理器:
@Bean
public BeanValidatingItemProcessor<Person> beanValidatingItemProcessor() throws Exception {
BeanValidatingItemProcessor<Person> beanValidatingItemProcessor = new BeanValidatingItemProcessor<>();
beanValidatingItemProcessor.setFilter(true);
return beanValidatingItemProcessor;
}
容错
回滚块时,在读取过程中缓存的项目可能会
再加工。如果将某个步骤配置为容错(通常使用 skip 或
重试处理)、任何ItemProcessor
used 的实现方式应为
幂等。通常,这包括不对
这ItemProcessor
并仅更新
实例,即结果。