物品处理

ItemReader 和 ItemWriter 接口在各自的任务中非常有用,但如果你想在写入前插入业务逻辑呢?两种读取和写入的一种选择是使用复合模式:创建一个物品写手包含 另一个物品写手物品阅读器包含另一个物品阅读器. 以下代码展示了一个示例:spring-doc.cadn.net.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;
    }
}

前一类包含另一个物品写手它在提供了一些业务逻辑后,将其委派给该模式可以轻松地用于物品阅读器如 嗯,也许是为了获得更多基于所提供的输入的参考数据 主要物品阅读器. 如果你需要控制呼叫,它也很有用你自己。 然而,如果你只是想在提交给写作的项目真正写成之前“转换”它,你就不必你自己。 你只需修改该项目即可。对于这个场景,Spring Batch 提供了物品处理器接口,如下所示接口定义显示:spring-doc.cadn.net.cn

public interface ItemProcessor<I, O> {

    O process(I item) throws Exception;
}

物品处理器很简单。给定一个对象,变换它并返回另一个对象。 这 前提是对象可能属于同一类型,也可能不同。关键是业务逻辑可以应用于进程中,而开发者完全需要自己去创建 逻辑。 一物品处理器可以直接接入一个步。例如,假设物品阅读器提供了一类 类型并且需要转换为类型酒吧在被写出之前。以下示例展示了一个物品处理器那个表演 转换:spring-doc.cadn.net.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
    }
}

在前面的例子中,有一个名为 的类,一个名为酒吧,以及一个类 叫Foo处理器这符合物品处理器接口。变换为 简单,但任何类型的变形都可以在这里完成。这律师写手酒吧如果提供了其他类型,则抛出异常。同样,Foo处理器如果不是提供。这Foo处理器然后可以注入到,如下示例所示:spring-doc.cadn.net.cn

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

区别物品处理器物品阅读器物品写手那是物品处理器对于 是可选的.spring-doc.cadn.net.cn

链化物品处理器

在很多场景下,只做一次变换很有用,但如果你想做呢 “链式”组合多个物品处理器实现?你可以通过以下方式实现 就是前面提到的复合形态。更新之前的内容,单身 变换,示例,被转换为酒吧,变换为福巴尔并写出,如下示例所示:spring-doc.cadn.net.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
    }
}

一个Foo处理器以及一个条形处理器可以“串联”起来得到福巴尔如下例所示:spring-doc.cadn.net.cn

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

就像前面的例子一样,你可以将复合处理器配置为:spring-doc.cadn.net.cn

Java 配置
@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;
}
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.infrastructure.item.support.CompositeItemProcessor">
    <property name="delegates">
        <list>
            <bean class="..FooProcessor" />
            <bean class="..BarProcessor" />
        </list>
    </property>
</bean>

过滤记录

项目处理器的一个典型用途是在记录传递前过滤掉它们 这物品写手.过滤是与跳过不同的动作。跳过表示 记录无效,而过滤表示记录不应无效 写。spring-doc.cadn.net.cn

例如,考虑一个批处理作业,读取包含三种不同类型 记录:需要插入的记录、需要更新的记录和需要删除的记录。如果记录删除 系统不支持,我们不希望发送任何可删除的记录到 这物品写手.然而,既然这些唱片其实并不算坏,我们也希望 过滤掉它们,而不是跳过它们。因此,物品写手只会收到 可插入且可更新的记录。spring-doc.cadn.net.cn

要筛选记录,你可以返回来自物品处理器.该框架检测 结果为并且避免将该项添加到交付记录列表中 这物品写手.一个例外,来自物品处理器结果为 跳。spring-doc.cadn.net.cn

验证输入

ItemReaders 和 ItemWriters 章节讨论了多种解析输入的方法。 每个主要实现如果不是“良好”都会抛出例外。这固定长度标记器如果缺少某一数据范围,会抛出异常。同样地 尝试访问索引行图仪FieldSetMapper不存在或 格式与预期不同会导致抛出异常。全部 这类例外会被抛在前面返回。然而,他们并未涉及相关内容 归还物品是否有效的问题。例如,如果 是年龄,不可能是负的。它之所以能正确解析,是因为它存在且 是一个数字,但它不会导致异常。因为已经有大量 Spring Batch 并不试图提供另一种验证框架。而是 提供一个简单的接口,称为验证器,你可以用任意数量的 实现 框架,正如以下接口定义所示:spring-doc.cadn.net.cn

public interface Validator<T> {

    void validate(T value) throws ValidationException;

}

合同内容是驗證如果对象无效,方法会抛出异常 如果有效,则正常返回。春季批次提供了验证项目处理器,正如以下Beans定义所示:spring-doc.cadn.net.cn

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;
}
XML 配置
<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)注释。例如,考虑以下类型:spring-doc.cadn.net.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;
    }

}

你可以通过声明BeanValidatingItemProcessor豆子在你的 应用上下文,并将其注册为针对区块的步骤中的处理器:spring-doc.cadn.net.cn

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

    return beanValidatingItemProcessor;
}

容错

当一个区块被回滚时,读取过程中被缓存的项目可能会被 再加工。如果某一步配置为容错(通常通过使用跳跃或 重试处理),任意物品处理器被使用后应以以下方式实现 幂等。通常这包括对 的输入项不做任何更改 这物品处理器并且仅更新 这就是结果。spring-doc.cadn.net.cn