Item processing

项目处理

ItemReader和ItemWriter接口对于其特定的 任务,但是如果您想在编写之前插入业务逻辑怎么办?两者一选一 读写就是使用复合模式:创建一个包含 another 或包含另一个 .以下内容 代码显示了一个例子:ItemWriterItemWriterItemReaderItemReaderspring-doc.cn

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;
    }
}

前面的类包含另一个类,它在具有 提供了一些业务逻辑。此模式可以很容易地用于 as 好吧,也许是为了根据 主要。如果您需要控制对自己的调用,它也很有用。 但是,如果您只想 “转换” 传入的项,以便在写入之前写入 其实写的,你不需要自己。您可以只修改项目。对于这个 场景中,Spring Batch 提供了如下接口 接口定义显示:ItemWriterItemReaderItemReaderwritewriteItemProcessorspring-doc.cn

public interface ItemProcessor<I, O> {

    O process(I item) throws Exception;
}

An 很简单。给定一个对象,转换它并返回另一个对象。这 提供的对象可能属于同一类型,也可能不是同一类型。关键是业务逻辑可以 在流程中应用,并且完全由开发人员来创建它 逻辑。An 可以直接连接到步骤中。例如,假设 an 提供了一个 type 类,并且需要在写出之前将其转换为 type。以下示例显示了执行 转换:ItemProcessorItemProcessorItemReaderFooBarItemProcessorspring-doc.cn

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
    }
}

在前面的示例中,有一个名为 、 名为 的类 和一个类 named 的 API 执行该接口。转换是 很简单,但任何类型的转换都可以在这里完成。写入对象,如果提供了任何其他类型,则引发异常。同样,如果提供了除 a 之外的任何内容,则 the 会引发异常。然后,可以将 注入到 中,如下例所示:FooBarFooProcessorItemProcessorBarWriterBarFooProcessorFooFooProcessorStepspring-doc.cn

XML 配置
<job id="ioSampleJob">
    <step name="step1">
        <tasklet>
            <chunk reader="fooReader" processor="fooProcessor" writer="barWriter"
                   commit-interval="2"/>
        </tasklet>
    </step>
</job>
Java 配置
@Bean
public Job ioSampleJob(JobRepository jobRepository) {
	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();
}

和 or 之间的区别在于 an 对于 .ItemProcessorItemReaderItemWriterItemProcessorStepspring-doc.cn

链接 ItemProcessors

在许多情况下,执行单个转换都很有用,但如果您想 将多个实现“链接”在一起?您可以通过使用 前面提到的复合模式。要更新上一个 转换(例如)转换为 ,后者被转换为并写出,如下例所示:ItemProcessorFooBarFoobarspring-doc.cn

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
    }
}

A 和 a 可以“链接”在一起以得到结果,如以下示例所示:FooProcessorBarProcessorFoobarspring-doc.cn

CompositeItemProcessor<Foo,Foobar> compositeProcessor =
                                      new CompositeItemProcessor<Foo,Foobar>();
List itemProcessors = new ArrayList();
itemProcessors.add(new FooProcessor());
itemProcessors.add(new BarProcessor());
compositeProcessor.setDelegates(itemProcessors);

与前面的示例一样,您可以将复合处理器配置为:Stepspring-doc.cn

XML 配置
<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>
Java 配置
@Bean
public Job ioSampleJob(JobRepository jobRepository) {
	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;
}

筛选记录

项目处理器的一个典型用途是在将记录传递给 这。筛选是一种不同于跳过的操作。跳过表示 记录无效,而筛选表示记录不应无效 写。ItemWriterspring-doc.cn

例如,考虑一个批处理作业,它读取包含三种不同类型的 记录:要插入的记录、要更新的记录和要删除的记录。如果记录删除 不受系统支持,我们不希望将任何可删除的记录发送到 这。但是,由于这些记录实际上并不是不良记录,因此我们希望 过滤掉它们而不是跳过它们。因此,将只接收 可插入和可更新的记录。ItemWriterItemWriterspring-doc.cn

要筛选记录,您可以从 .框架检测 ,并避免将该项目添加到传递到 这。从 跳。nullItemProcessornullItemWriterItemProcessorspring-doc.cn

验证输入

ItemReaders和ItemWriters一章讨论了解析 Importing 的多种方法。 如果每个主要实现不是 “格式正确” ,则会引发异常。如果缺少数据范围,则引发异常。同样地 尝试访问不存在的 OR 中的索引,或者 的格式与预期的格式不同,会导致引发异常。全部 这些类型的异常在 return 之前引发。但是,它们没有解决 返回的项目是否有效的问题。例如,如果其中一个字段 是一个年龄,它不能是负数。它可能会正确解析,因为它存在并且 是一个数字,但不会导致异常。由于已经有大量的 验证框架,Spring Batch 不会尝试提供另一个。相反,它 提供了一个名为 的简单接口,您可以通过任意数量的 frameworks,如下面的接口定义所示:FixedLengthTokenizerRowMapperFieldSetMapperreadValidatorspring-doc.cn

public interface Validator<T> {

    void validate(T value) throws ValidationException;

}

协定是,如果对象无效,该方法将引发异常 如果有效,则正常返回。Spring Batch 提供了一个 ,如下面的 bean 定义所示:validateValidatingItemProcessorspring-doc.cn

XML 配置
<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>
Java 配置
@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) 注释。例如,请考虑以下类型:BeanValidatingItemProcessorPersonspring-doc.cn

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 的步骤中将其注册为处理器:BeanValidatingItemProcessorspring-doc.cn

@Bean
public BeanValidatingItemProcessor<Person> beanValidatingItemProcessor() throws Exception {
    BeanValidatingItemProcessor<Person> beanValidatingItemProcessor = new BeanValidatingItemProcessor<>();
    beanValidatingItemProcessor.setFilter(true);

    return beanValidatingItemProcessor;
}

容错

回滚块时,在读取过程中缓存的项目可能会 再加工。如果将某个步骤配置为容错(通常使用 skip 或 retry 处理),则任何 used 都应以 幂等。通常,这包括不对 ,并且仅更新 实例,即结果。ItemProcessorItemProcessorspring-doc.cn