Spring Batch -配置步骤 (XML/Java)

这篇具有很好参考价值的文章主要介绍了Spring Batch -配置步骤 (XML/Java)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

面向块的处理

Spring Batch 在最常见的情况下使用“面向块”的处理方式 实现。面向块的处理是指一次读取一个数据, 创建在事务边界内写出的“块”。一次的数量 读取的项目等于提交间隔,整个块由 写出,然后提交事务。

以下伪代码以简化的形式显示了​​ItemWriter​​相同的概念:

List items = new Arraylist();
for(int i = 0; i < commitInterval; i++){
    Object item = itemReader.read();
    if (item != null) {
        items.add(item);
    }
}
itemWriter.write(items);

可以配置一个面向块的步骤,其中包含一个可选的步骤,以便在将项目传递

以下伪代码显示了如何以简化的形式实现​​ItemProcessor​​​​ ItemWriter​​​​ ItemProcessor​​这一点:

List items = new Arraylist();
for(int i = 0; i < commitInterval; i++){
    Object item = itemReader.read();
    if (item != null) {
        items.add(item);
    }
}

List processedItems = new Arraylist();
for(Object item: items){
    Object processedItem = itemProcessor.process(item);
    if (processedItem != null) {
        processedItems.add(processedItem);
    }
}

itemWriter.write(processedItems);

有关项目处理器及其用例的更多详细信息,请参阅项目处理部分。
配置步骤

尽管 所需的依赖项列表相对较短,但它是一个 极其复杂的类,可能包含许多协作者。​​Step​​

为了简化配置,您可以使用Spring Batch XML命名空间,如 以下示例显示:

例 1.XML 配置

<job id="sampleJob" job-repository="jobRepository">
    <step id="step1">
        <tasklet transaction-manager="transactionManager">
            <chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
        </tasklet>
    </step>
</job>

使用 Java 配置时,您可以使用 Spring Batch 构建器,作为 以下示例显示:

例 2.Java配置

/**
 * Note the JobRepository is typically autowired in and not needed to be explicitly
 * configured
 */
@Bean
public Job sampleJob(JobRepository jobRepository, Step sampleStep) {
    return new JobBuilder("sampleJob", jobRepository)
                .start(sampleStep)
                .build();
}

/**
 * Note the TransactionManager is typically autowired in and not needed to be explicitly
 * configured
 */
@Bean
public Step sampleStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return new StepBuilder("sampleStep", jobRepository)
                .<String, String>chunk(10, transactionManager)
                .reader(itemReader())
                .writer(itemWriter())
                .build();
}

从父级继承​​Step​​

如果一组共享类似的配置,那么定义一个 混凝土可能从中继承属性的“父项”。类似于类 继承 在 Java 中,“子”将其元素和属性与 父母的。孩子还会覆盖任何父母的 .​​Steps​​​​Step​​​​Steps​​​​Step​​​​Steps​​

在下面的示例中,, 继承自 。是的 使用 、、 和 实例化。此外,是 ,因为它是 被 覆盖,如以下示例所示:​​Step​​​​concreteStep1​​​​parentStep​​​​itemReader​​​​itemProcessor​​​​itemWriter​​​​startLimit=5​​​​allowStartIfComplete=true​​​​commitInterval​​​​5​​​​concreteStep1​​​​Step​​

<step id="parentStep">
    <tasklet allow-start-if-complete="true">
        <chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
    </tasklet>
</step>

<step id="concreteStep1" parent="parentStep">
    <tasklet start-limit="5">
        <chunk processor="itemProcessor" commit-interval="5"/>
    </tasklet>
</step>

抽象​​Step​​

有时,可能需要定义一个不是完整配置的父级。例如,如果 、 和 属性是 离开配置,则初始化失败。如果父母必须是 在没有一个或多个这些属性的情况下定义,则应使用该属性。an 只是扩展,从不实例化。​​Step​​​​Step​​​​reader​​​​writer​​​​tasklet​​​​Step​​​​abstract​​​​abstract​​​​Step​​

在下面的示例中,如果 () 没有被宣布为抽象的。、() 具有 、 和 。​​Step​​​​abstractParentStep​​​​Step​​​​concreteStep2​​​​itemReader​​​​itemWriter​​​​commit-interval=10​​

<step id="abstractParentStep" abstract="true">
    <tasklet>
        <chunk commit-interval="10"/>
    </tasklet>
</step>

<step id="concreteStep2" parent="abstractParentStep">
    <tasklet>
        <chunk reader="itemReader" writer="itemWriter"/>
    </tasklet>
</step>

合并列表

上的一些可配置元素是列表,例如元素。 如果父元素和子元素都声明一个元素,则 子项列表将覆盖父项的列表。允许孩子添加其他 侦听器 对于父级定义的列表,每个列表元素都有一个属性。 如果元素指定 ,则子列表与 父级的,而不是覆盖它。​​Steps​​​​​​​​Steps​​​​​​​​merge​​​​merge="true"​​

在下面的示例中,“concreteStep3”是使用两个侦听器创建的:和 :​​Step​​​​listenerOne​​​​listenerTwo​​

<step id="listenersParentStep" abstract="true">
    <listeners>
        <listener ref="listenerOne"/>
    <listeners>
</step>

<step id="concreteStep3" parent="listenersParentStep">
    <tasklet>
        <chunk reader="itemReader" writer="itemWriter" commit-interval="5"/>
    </tasklet>
    <listeners merge="true">
        <listener ref="listenerTwo"/>
    <listeners>
</step>

提交间隔

如前所述,步骤读入和写出项目,定期提交 通过使用提供的 .如果为 1,则为 在写入每个单独的项目后提交。在许多情况下,这不太理想, 因为开始和提交交易是昂贵的。理想情况下,最好是 在每笔交易中处理尽可能多的项目,这完全取决于 正在处理的数据类型以及步骤与之交互的资源。 因此,您可以配置在提交中处理的项目数。​​PlatformTransactionManager​​​​commit-interval​​

下面的示例显示 其值为 10,因为它将在 XML 中定义:​​step​​​​tasklet​​​​commit-interval​​

XML 配置

<job id="sampleJob">
    <step id="step1">
        <tasklet>
            <chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
        </tasklet>
    </step>
</job>

以下示例显示了 a 其值为 10,因为它将在 Java 中定义:​​step​​​​tasklet​​​​commit-interval​​

爪哇配置

@Bean
public Job sampleJob(JobRepository jobRepository) {
    return new JobBuilder("sampleJob", jobRepository)
                     .start(step1())
                     .build();
}

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return tnew StepBuilder("step1", jobRepository)
                .<String, String>chunk(10, transactionManager)
                .reader(itemReader())
                .writer(itemWriter())
                .build();
}

在前面的示例中,每个事务中处理 10 个项目。在 开始处理,交易开始。此外,每次在 上调用 时,计数器都会递增。当它达到 10 时,聚合项目列表 传递给 ,并提交事务。​​read​​​​ItemReader​​​​ItemWriter​​
为重新启动配置​​Step​​

在 “配置和运行作业” 一节中,讨论了重新启动 的问题。重新启动会对步骤产生许多影响,因此可能会 需要一些特定的配置。​​Job​​
设置启动限制

在许多情况下,您可能希望控制一次可以的次数 开始。例如,您可能需要配置特定的可能,以便 仅运行一次,因为它使某些必须手动修复的资源失效,然后才能运行 再次运行。这是可以在步骤级别配置的,因为不同的步骤可能有 不同的要求。只能执行一次的 A 可以作为 与可以无限运行的 a 相同。​​Step​​​​Step​​​​Step​​​​Job​​​​Step​​

以下代码片段显示了 XML 中的启动限制配置示例:

XML 配置

<step id="step1">
    <tasklet start-limit="1">
        <chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
    </tasklet>
</step>

以下代码片段显示了 Java 中的启动限制配置示例:

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(10, transactionManager)
        .reader(itemReader())
        .writer(itemWriter())
        .startLimit(1)
        .build();
}

前面示例中所示的步骤只能运行一次。尝试再次运行它 导致 被抛出。请注意,默认值为 启动限制为 。​​StartLimitExceededException​​​​Integer.MAX_VALUE​​
重新启动已完成的​​Step​​

对于可重新启动的作业,可能始终存在一个或多个步骤 运行,无论他们第一次是否成功。一个例子可能是 是验证步骤或在处理之前清理资源。在 重新启动作业的正常处理,状态为 (表示它) 的任何步骤 已成功完成),将被跳过。设置为 将覆盖此设置,以便步骤始终运行。​​Step​​​​COMPLETED​​​​allow-start-if-complete​​​​true​​

以下代码片段演示如何在 XML 中定义可重新启动的作业:

XML 配置

<step id="step1">
    <tasklet allow-start-if-complete="true">
        <chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
    </tasklet>
</step>

以下代码片段演示如何在 Java 中定义可重新启动的作业:

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(10, transactionManager)
        .reader(itemReader())
        .writer(itemWriter())
        .allowStartIfComplete(true)
        .build();
}

​​Step​​重新启动配置示例

下面的 XML 示例演示如何将作业配置为具有可以 重新 启动:

XML 配置

<job id="footballJob" restartable="true">
    <step id="playerload" next="gameLoad">
        <tasklet>
            <chunk reader="playerFileItemReader" writer="playerWriter"
                   commit-interval="10" />
        </tasklet>
    </step>
    <step id="gameLoad" next="playerSummarization">
        <tasklet allow-start-if-complete="true">
            <chunk reader="gameFileItemReader" writer="gameWriter"
                   commit-interval="10"/>
        </tasklet>
    </step>
    <step id="playerSummarization">
        <tasklet start-limit="2">
            <chunk reader="playerSummarizationSource" writer="summaryWriter"
                   commit-interval="10"/>
        </tasklet>
    </step>
</job>

The following Java example shows how to configure a job to have steps that can be restarted:

Java Configuration

@Bean
public Job footballJob(JobRepository jobRepository) {
  return new JobBuilder("footballJob", jobRepository)
        .start(playerLoad())
        .next(gameLoad())
        .next(playerSummarization())
        .build();
}

@Bean
public Step playerLoad(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return new StepBuilder("playerLoad", jobRepository)
      .<String, String>chunk(10, transactionManager)
      .reader(playerFileItemReader())
      .writer(playerWriter())
      .build();
}

@Bean
public Step gameLoad(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return new StepBuilder("gameLoad", jobRepository)
      .allowStartIfComplete(true)
      .<String, String>chunk(10, transactionManager)
      .reader(gameFileItemReader())
      .writer(gameWriter())
      .build();
}

@Bean
public Step playerSummarization(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return new StepBuilder("playerSummarization", jobRepository)
      .startLimit(2)
      .<String, String>chunk(10, transactionManager)
      .reader(playerSummarizationSource())
      .writer(summaryWriter())
      .build();
}

配置跳过逻辑

在许多情况下,处理时遇到的错误不应导致失败,而应跳过。这通常是一个必须的决定 由了解数据本身及其含义的人制作。财务数据, 例如,可能无法跳过,因为它会导致资金被转移,这 需要完全准确。另一方面,加载供应商列表可能会 允许跳过。如果供应商因格式不正确或 缺少必要的信息,可能没有问题。通常,这些不好 记录也会被记录,稍后在讨论侦听器时将对此进行介绍。​​Step​​

以下 XML 示例显示了使用跳过限制的示例:

XML 配置

<step id="step1">
   <tasklet>
      <chunk reader="flatFileItemReader" writer="itemWriter"
             commit-interval="10" skip-limit="10">
         <skippable-exception-classes>
            <include class="org.springframework.batch.item.file.FlatFileParseException"/>
         </skippable-exception-classes>
      </chunk>
   </tasklet>
</step>

以下 Java 示例显示了使用跳过限制的示例:

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(10, transactionManager)
        .reader(flatFileItemReader())
        .writer(itemWriter())
        .faultTolerant()
        .skipLimit(10)
        .skip(FlatFileParseException.class)
        .build();
}

在前面的示例中,使用了 a。如果在任何时候抛出 a,则跳过该项目并计入总数 跳过限制为 10。声明的异常(及其子类)可能会引发 在块处理的任何阶段(读取、处理或写入)。单独的计数 由内部读取、处理和写入的跳过组成 步骤执行,但限制适用于所有跳过。一旦跳过限制为 已达到,则找到下一个异常会导致步骤失败。换句话说,第十一 跳过会触发异常,而不是第十个。​​FlatFileItemReader​​​​FlatFileParseException​​

前面的示例的一个问题是,除 a 之外的任何其他异常都会导致失败。在某些情况下,这可能是 正确的行为。但是,在其他情况下,可能更容易识别哪个 异常应导致失败并跳过其他所有内容。​​FlatFileParseException​​​​Job​​

以下 XML 示例显示排除特定异常的示例:

XML 配置

<step id="step1">
    <tasklet>
        <chunk reader="flatFileItemReader" writer="itemWriter"
               commit-interval="10" skip-limit="10">
            <skippable-exception-classes>
                <include class="java.lang.Exception"/>
                <exclude class="java.io.FileNotFoundException"/>
            </skippable-exception-classes>
        </chunk>
    </tasklet>
</step>

以下 Java 示例显示了一个排除特定异常的示例:

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(10, transactionManager)
        .reader(flatFileItemReader())
        .writer(itemWriter())
        .faultTolerant()
        .skipLimit(10)
        .skip(Exception.class)
        .noSkip(FileNotFoundException.class)
        .build();
}

通过标识为可跳过的异常类,配置 表示所有内容都是可跳过的。但是,通过“排除”,配置会细化可跳过的列表 异常类为除 之外的所有类。任何排除 如果遇到异常类,则为致命类(即,不会跳过它们)。​​java.lang.Exception​​​​Exceptions​​​​java.io.FileNotFoundException​​​​Exceptions​​​​FileNotFoundException​​

对于遇到的任何异常,可跳过性由最近的超类确定 在类层次结构中。任何未分类的异常都被视为“致命”。
配置重试逻辑

在大多数情况下,您希望异常导致跳过或失败。然而 并非所有异常都是确定性的。如果遇到 阅读,它总是被抛出那个记录。重置无济于事。 但是,对于其他例外情况(例如 , 指示当前进程已尝试更新另一个进程的记录 保持锁定),等待并重试可能会导致成功。​​Step​​​​FlatFileParseException​​​​ItemReader​​​​DeadlockLoserDataAccessException​​

在 XML 中,重试应按如下方式配置:

<step id="step1">
   <tasklet>
      <chunk reader="itemReader" writer="itemWriter"
             commit-interval="2" retry-limit="3">
         <retryable-exception-classes>
            <include class="org.springframework.dao.DeadlockLoserDataAccessException"/>
         </retryable-exception-classes>
      </chunk>
   </tasklet>
</step>

在 Java 中,重试应配置如下:

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(2, transactionManager)
        .reader(itemReader())
        .writer(itemWriter())
        .faultTolerant()
        .retryLimit(3)
        .retry(DeadlockLoserDataAccessException.class)
        .build();
}

允许对单个项目可以重试的次数限制,并且 “可重试”的异常列表。您可以在重试中找到有关重试工作原理的更多详细信息。​​Step​​
控制回滚

默认情况下,无论重试还是跳过,引发的任何异常都会导致事务由 回滚控制。如果跳过配置为 如前所述,从 引发的异常不会导致回滚。 但是,在许多情况下,从应该 不会导致回滚,因为尚未执行任何操作以使事务无效。 因此,您可以使用不应的例外列表配置 导致回滚。​​ItemWriter​​​​Step​​​​ItemReader​​​​ItemWriter​​​​Step​​

在 XML 中,可以按如下方式控制回滚:

XML 配置

<step id="step1">
   <tasklet>
      <chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
      <no-rollback-exception-classes>
         <include class="org.springframework.batch.item.validator.ValidationException"/>
      </no-rollback-exception-classes>
   </tasklet>
</step>

在 Java 中,您可以按如下方式控制回滚:

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(2, transactionManager)
        .reader(itemReader())
        .writer(itemWriter())
        .faultTolerant()
        .noRollback(ValidationException.class)
        .build();
}

事务性读取器

的基本合同是它仅是远期的。步进缓冲器 读取器输入,以便在回滚时不需要重新读取项目 来自读者。但是,在某些情况下,读者是建立在 事务资源(如 JMS 队列)的顶部。在这种情况下,由于队列是 绑定到回滚的事务,已从 队列重新打开。因此,您可以将步骤配置为不缓冲 项目。​​ItemReader​​

下面的示例演示如何创建不缓冲 XML 中的项的读取器:

XML 配置

<step id="step1">
    <tasklet>
        <chunk reader="itemReader" writer="itemWriter" commit-interval="2"
               is-reader-transactional-queue="true"/>
    </tasklet>
</step>

以下示例演示如何创建不在 Java 中缓冲项的读取器:

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(2, transactionManager)
        .reader(itemReader())
        .writer(itemWriter())
        .readerIsTransactionalQueue()
        .build();
}

交易属性

您可以使用事务属性来控制 、 和 设置。您可以在 中找到有关设置交易属性的更多信息 春天 核心文档。​​isolation​​​​propagation​​​​timeout​​

以下示例设置 、 和 事务 XML 中的属性:​​isolation​​​​propagation​​​​timeout​​

XML 配置

<step id="step1">
    <tasklet>
        <chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
        <transaction-attributes isolation="DEFAULT"
                                propagation="REQUIRED"
                                timeout="30"/>
    </tasklet>
</step>

以下示例设置 、 和 事务 Java 中的属性:​​isolation​​​​propagation​​​​timeout​​

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  DefaultTransactionAttribute attribute = new DefaultTransactionAttribute();
  attribute.setPropagationBehavior(Propagation.REQUIRED.value());
  attribute.setIsolationLevel(Isolation.DEFAULT.value());
  attribute.setTimeout(30);

  return new StepBuilder("step1", jobRepository)
        .<String, String>chunk(2, transactionManager)
        .reader(itemReader())
        .writer(itemWriter())
        .transactionAttribute(attribute)
        .build();
}

注册时​​ItemStream​​​​Step​​

该步骤必须在其必要的点处理回调 生命周期。(有关接口的详细信息,请参阅项流)。如果一个步骤失败并且可能 需要重新启动,因为接口是步骤获取的位置 它需要的有关执行之间的持久状态的信息。​​ItemStream​​​​ItemStream​​​​ItemStream​​

如果 、 或 本身实现了接口,则会自动注册这些接口。任何其他流都需要 单独注册。这通常是间接依赖关系的情况,例如 委托被注入到读取器和编写器中。您可以在 通过元素上注册流。​​ItemReader​​​​ItemProcessor​​​​ItemWriter​​​​ItemStream​​​​step​​​​stream​​

下面的示例演示如何在 XML 中注册 :​​stream​​​​step​​

XML 配置

<step id="step1">
    <tasklet>
        <chunk reader="itemReader" writer="compositeWriter" commit-interval="2">
            <streams>
                <stream ref="fileItemWriter1"/>
                <stream ref="fileItemWriter2"/>
            </streams>
        </chunk>
    </tasklet>
</step>

<beans:bean id="compositeWriter"
            class="org.springframework.batch.item.support.CompositeItemWriter">
    <beans:property name="delegates">
        <beans:list>
            <beans:ref bean="fileItemWriter1" />
            <beans:ref bean="fileItemWriter2" />
        </beans:list>
    </beans:property>
</beans:bean>

以下示例显示了如何在 Java 中注册 a:​​stream​​​​step​​

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(2, transactionManager)
        .reader(itemReader())
        .writer(compositeItemWriter())
        .stream(fileItemWriter1())
        .stream(fileItemWriter2())
        .build();
}

/**
 * In Spring Batch 4, the CompositeItemWriter implements ItemStream so this isn't
 * necessary, but used for an example.
 */
@Bean
public CompositeItemWriter compositeItemWriter() {
  List<ItemWriter> writers = new ArrayList<>(2);
  writers.add(fileItemWriter1());
  writers.add(fileItemWriter2());

  CompositeItemWriter itemWriter = new CompositeItemWriter();

  itemWriter.setDelegates(writers);

  return itemWriter;
}

在前面的示例中,不是 ,而是其 代表是。因此,两个委托编写器都必须显式注册为流 以便框架正确处理它们。不需要 显式注册为流,因为它是 的直接属性。步骤 现在可以重新启动,并且读取器和写入器的状态正确保留在 故障事件。​​CompositeItemWriter​​​​ItemStream​​​​ItemReader​​​​Step​​
拦截执行​​Step​​

与 一样,在执行 a 的过程中有许多事件,其中 用户可能需要执行某些功能。例如,写出到平面 需要页脚的文件,需要通知何时 已完成,以便可以写入页脚。这可以通过许多作用域侦听器之一来实现。​​Job​​​​Step​​​​ItemWriter​​​​Step​​​​Step​​

您可以应用实现 (但不是该接口)之一的扩展的任何类 本身,因为它是空的)来逐步完成元素。 该元素在步骤、任务集或块声明中有效。我们 建议您在其函数应用的级别声明侦听器 或者,如果它是多功能的(例如和), 在适用的最精细级别声明它。​​StepListener​​​​listeners​​​​listeners​​​​StepExecutionListener​​​​ItemReadListener​​

以下示例显示了在 XML 中在块级别应用的侦听器:

XML 配置

<step id="step1">
    <tasklet>
        <chunk reader="reader" writer="writer" commit-interval="10"/>
        <listeners>
            <listener ref="chunkListener"/>
        </listeners>
    </tasklet>
</step>

以下示例显示了在 Java 中在块级别应用的侦听器:

Java配置

@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return tnew StepBuilder("step1", jobRepository)
        .<String, String>chunk(10, transactionManager)
        .reader(reader())
        .writer(writer())
        .listener(chunkListener())
        .build();
}

本身实现其中一个接口的、 或 会自动注册到 if 使用 命名空间元素或工厂之一。这仅 适用于直接注入 .如果侦听器嵌套在 另一个组件,您需要显式注册它(如前面使用步骤注册 ItemStream 中所述)。​​ItemReader​​​​ItemWriter​​​​ItemProcessor​​​​StepListener​​​​Step​​​​​​​​*StepFactoryBean​​​​Step​​

除了接口之外,还提供了注释以解决 同样的担忧。普通的旧 Java 对象可以具有具有这些注释的方法,这些注释是 然后转换为相应的类型。注释也很常见 区块组件的自定义实现,例如 OR 或 .注释由元素的 XML 解析器进行分析 以及使用构建器中的方法注册,所以你需要做的一切 是使用 XML 命名空间或生成器向步骤注册侦听器。​​StepListener​​​​StepListener​​​​ItemReader​​​​ItemWriter​​​​Tasklet​​​​​​​​listener​​
​​StepExecutionListener​​

​​StepExecutionListener​​表示用于执行的最通用侦听器。它 允许在 开始之前和结束之后发出通知,无论它是否结束 正常或失败,如以下示例所示:​​Step​​​​Step​​

public interface StepExecutionListener extends StepListener {

    void beforeStep(StepExecution stepExecution);

    ExitStatus afterStep(StepExecution stepExecution);

}

​​ExitStatus​​具有返回类型 ,以便让侦听器有机会 修改完成 时返回的退出代码。​​afterStep​​​​Step​​
与此接口对应的注释是:

​​@BeforeStep​​
​​@AfterStep​​

​​ChunkListener​​

“块”定义为在事务范围内处理的项目。提交一个 事务在每个提交间隔提交一个块。您可以使用 在区块开始处理之前或区块完成后执行逻辑 成功,如以下接口定义所示:​​ChunkListener​​

public interface ChunkListener extends StepListener {

    void beforeChunk(ChunkContext context);
    void afterChunk(ChunkContext context);
    void afterChunkError(ChunkContext context);

}

beforeChunk 方法在事务启动后但在读取开始之前调用 在 .相反,在块被调用后调用 已提交(如果有回滚,则根本不提交)。​​ItemReader​​​​afterChunk​​

与此接口对应的注释是:

  ​​@BeforeChunk​​
    ​​@AfterChunk​​
    ​​@AfterChunkError​​

您可以在没有块声明时应用 。这是 负责调用 ,因此它适用于非面向项的任务 以及(它在任务之前和之后被调用)。​​ChunkListener​​​​TaskletStep​​​​ChunkListener​​
​​ItemReadListener​​

在之前讨论跳过逻辑时,有人提到日志可能是有益的 跳过的记录,以便以后可以处理它们。在读取错误的情况下, 这可以通过 完成,如以下接口 定义显示:​​ItemReaderListener​​

public interface ItemReadListener<T> extends StepListener {

    void beforeRead();
    void afterRead(T item);
    void onReadError(Exception ex);

}

在每次调用之前调用该方法以读取 .该方法在每次成功调用读取后调用,并传递项目 那被读了。如果读取时出错,则调用该方法。 提供了遇到的异常,以便可以记录它。​​beforeRead​​​​ItemReader​​​​afterRead​​​​onReadError​​

与此接口对应的注释是:

  ​​@BeforeRead​​
    ​​@AfterRead​​
    ​​@OnReadError​​

​​ItemProcessListener​​

与 一样,可以“侦听”项目的处理,如 以下接口定义显示:​​ItemReadListener​​

public interface ItemProcessListener<T, S> extends StepListener {

    void beforeProcess(T item);
    void afterProcess(T item, S result);
    void onProcessError(T item, Exception e);

}

该方法在 和 之前调用 递上要处理的项目。该方法在 项目已成功处理。如果在处理时出错,则调用该方法。遇到的异常和 提供尝试处理,以便可以记录它们。​​beforeProcess​​​​process​​​​ItemProcessor​​​​afterProcess​​​​onProcessError​​

与此接口对应的注释是:

 ​​@BeforeProcess​​
    ​​@AfterProcess​​
    ​​@OnProcessError​​

​​ItemWriteListener​​

您可以使用 “侦听”项目的写入,作为 以下接口定义显示:​​ItemWriteListener​​

public interface ItemWriteListener<S> extends StepListener {

    void beforeWrite(List<? extends S> items);
    void afterWrite(List<? extends S> items);
    void onWriteError(Exception exception, List<? extends S> items);

}

该方法在之前被调用,并被交给 写入的项目列表。该方法在项目被调用后调用 写得成功。如果在写入时出现错误,则方法是 叫。遇到的异常和尝试写入的项目是 提供,以便可以记录它们。​​beforeWrite​​​​write​​​​ItemWriter​​​​afterWrite​​​​onWriteError​​

与此接口对应的注释是:

 ​​@BeforeWrite​​
    ​​@AfterWrite​​
    ​​@OnWriteError​​

​​SkipListener​​

​​ItemReadListener​​、 和 都提供机制 收到错误通知,但没有通知您记录实际上已被 跳。,例如,即使重试项目,也会调用,并且 成功的。因此,有一个单独的界面用于跟踪跳过的项目,如 以下接口定义显示:​​ItemProcessListener​​​​ItemWriteListener​​​​onWriteError​​

public interface SkipListener<T,S> extends StepListener {

    void onSkipInRead(Throwable t);
    void onSkipInProcess(T item, Throwable t);
    void onSkipInWrite(S item, Throwable t);

}

​​onSkipInRead​​每当在读取时跳过项目时都会调用。应该注意的是 该回滚可能会导致同一项目注册为多次跳过。 在写入时跳过项目时调用。因为该项目具有 已成功读取(而不是跳过),它还作为项目本身提供 论点。​​onSkipInWrite​​

与此接口对应的注释是:

​​@OnSkipInRead​​
​​@OnSkipInWrite​​
​​@OnSkipInProcess​​

跳过侦听器和事务

最常见的用例之一是注销跳过的项目,因此 另一个批处理过程甚至人工过程可用于评估和修复 导致跳过的问题。因为有很多情况下原始交易 可以回滚,Spring Batch做出两个保证:​​SkipListener​​

仅调用一次相应的 skip 方法(取决于错误发生的时间) 每件。
总是在提交事务之前调用。这是 确保侦听器的任何事务资源调用都不会被 中的故障。
SkipListener ItemWriter

​​TaskletStep​​

面向块的处理并不是在 中处理的唯一方法。如果必须包含存储过程调用,该怎么办?你可以 将调用实现为 AN 并在过程完成后返回 null。 但是,这样做有点不自然,因为需要 无操作 . Spring Batch 为这种情况提供了。​​Step​​​​Step​​​​ItemReader​​​​ItemWriter​​​​TaskletStep​​

接口有一个方法,称为 反复通过,直到它返回或抛出 指示失败的异常。对 的每次调用都包装在一个事务中。 实现者可以调用存储过程、脚本或 SQL 更新 陈述。​​Tasklet​​​​execute​​​​TaskletStep​​​​RepeatStatus.FINISHED​​​​Tasklet​​​​Tasklet​​

如果它实现了接口,则会自动将 tasklet 注册为 .​​StepListener​​​​TaskletStep​​​​StepListener​​
​​TaskletAdapter​​

与 和接口的其他适配器一样,该接口包含一个实现,允许将自身适应任何预先存在的 .class:。这可能有用的一个例子是现有的 DAO 用于更新一组记录上的标志。您可以使用 来调用此 类,而无需为接口编写适配器。​​ItemReader​​​​ItemWriter​​​​Tasklet​​​​TaskletAdapter​​​​TaskletAdapter​​​​Tasklet​​

下面的示例演示如何在 XML 中定义 :​​TaskletAdapter​​

XML 配置

<bean id="myTasklet" class="o.s.b.core.step.tasklet.MethodInvokingTaskletAdapter">
    <property name="targetObject">
        <bean class="org.mycompany.FooDao"/>
    </property>
    <property name="targetMethod" value="updateFoo" />
</bean>

以下示例显示了如何在 Java 中定义 a:​​TaskletAdapter​​

Java配置

@Bean
public MethodInvokingTaskletAdapter myTasklet() {
  MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter();

  adapter.setTargetObject(fooDao());
  adapter.setTargetMethod("updateFoo");

  return adapter;
}

实现示例​​Tasklet​​

许多批处理作业包含在主处理开始之前必须完成的步骤, 设置各种资源或在处理完成后清理这些资源 资源。对于大量处理文件的作业,通常需要 将某些文件成功上传到另一个文件后,在本地删除这些文件 位置。以下示例(取自 Spring 批处理示例项目)就是具有以下责任的实现:​​Tasklet​​

public class FileDeletingTasklet implements Tasklet, InitializingBean {

    private Resource directory;

    public RepeatStatus execute(StepContribution contribution,
                                ChunkContext chunkContext) throws Exception {
        File dir = directory.getFile();
        Assert.state(dir.isDirectory());

        File[] files = dir.listFiles();
        for (int i = 0; i < files.length; i++) {
            boolean deleted = files[i].delete();
            if (!deleted) {
                throw new UnexpectedJobExecutionException("Could not delete file " +
                                                          files[i].getPath());
            }
        }
        return RepeatStatus.FINISHED;
    }

    public void setDirectoryResource(Resource directory) {
        this.directory = directory;
    }

    public void afterPropertiesSet() throws Exception {
        Assert.state(directory != null, "directory must be set");
    }
}

前面的实现删除给定目录中的所有文件。它 应该注意的是,该方法只调用一次。剩下的就是 从 引用 。​​tasklet​​​​execute​​​​tasklet​​​​step​​

下面的示例演示如何从 XML 中引用 :​​tasklet​​​​step​​

XML 配置

<job id="taskletJob">
    <step id="deleteFilesInDir">
       <tasklet ref="fileDeletingTasklet"/>
    </step>
</job>

<beans:bean id="fileDeletingTasklet"
            class="org.springframework.batch.sample.tasklet.FileDeletingTasklet">
    <beans:property name="directoryResource">
        <beans:bean id="directory"
                    class="org.springframework.core.io.FileSystemResource">
            <beans:constructor-arg value="target/test-outputs/test-dir" />
        </beans:bean>
    </beans:property>
</beans:bean>

以下示例显示了如何从 Java 中引用 :​​tasklet​​​​step​​

Java配置

@Bean
public Job taskletJob(JobRepository jobRepository) {
  return new JobBuilder("taskletJob", jobRepository)
        .start(deleteFilesInDir())
        .build();
}

@Bean
public Step deleteFilesInDir(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
  return new StepBuilder("deleteFilesInDir", jobRepository)
        .tasklet(fileDeletingTasklet(), transactionManager)
        .build();
}

@Bean
public FileDeletingTasklet fileDeletingTasklet() {
  FileDeletingTasklet tasklet = new FileDeletingTasklet();

  tasklet.setDirectoryResource(new FileSystemResource("target/test-outputs/test-dir"));

  return tasklet;
}

控制步进流

由于能够在拥有作业中将步骤组合在一起,因此需要能够 控制作业如何从一个步骤“流动”到另一个步骤。的失败不 必然意味着应该失败。此外,可能有多种类型 的“成功”,决定接下来应该执行哪个。取决于如何 组已配置,某些步骤甚至可能根本不被处理。​​Step​​​​Job​​​​Step​​​​Steps​​
顺序流

最简单的流方案是所有步骤按顺序执行的作业,如 下图显示:

Spring Batch -配置步骤_重新启动_05

图4.顺序流

这可以通过在 中使用 来实现。​​next​​​​step​​

下面的示例演示如何在 XML 中使用该属性:​​next​​

XML 配置

<job id="job">
    <step id="stepA" parent="s1" next="stepB" />
    <step id="stepB" parent="s2" next="stepC"/>
    <step id="stepC" parent="s3" />
</job>

以下示例演示如何在 Java 中使用该方法:​​next()​​

Java配置

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
        .start(stepA())
        .next(stepB())
        .next(stepC())
        .build();
}

在上面的场景中,首先运行,因为它是第一个列出的。如果正常完成,则运行,依此类推。但是,如果失败, 整个失败且不执行。​​stepA​​​​Step​​​​stepA​​​​stepB​​​​step A​​​​Job​​​​stepB​​

对于 Spring Batch XML 命名空间,配置中列出的第一步始终是 .其他步骤元素的顺序不 很重要,但第一步必须始终首先出现在 XML 中。​​Job​​
条件流

在前面的示例中,只有两种可能性:

成功,应执行下一个。stepstep
失败了,因此,应该失败。stepjob

在许多情况下,这可能就足够了。但是,在这种情况下呢 一个失败应该触发一个不同的,而不是导致失败?

为了处理更复杂的场景,Spring Batch XML 命名空间允许您定义转换 步骤元素中的元素。一个这样的过渡是元素。与属性一样,元素告诉哪个 接下来执行。但是,与属性不同的是,允许任意数量的元素 给定的,并且在失败的情况下没有默认行为。这意味着,如果 使用过渡元素,过渡的所有行为都必须 显式定义。另请注意,单个步骤不能同时具有属性和 一个元素。​​next​​​​next​​​​next​​​​Job​​​​Step​​​​next​​​​Step​​​​Step​​​​next​​​​transition​​

该元素指定要匹配的模式以及接下来要执行的步骤,如 以下示例显示:​​next​​

XML 配置

<job id="job">
    <step id="stepA" parent="s1">
        <next on="*" to="stepB" />
        <next on="FAILED" to="stepC" />
    </step>
    <step id="stepB" parent="s2" next="stepC" />
    <step id="stepC" parent="s3" />
</job>

Java API 提供了一组流畅的方法,允许您指定流程和操作 当步骤失败时。下面的示例演示如何指定一个步骤 (),然后 继续执行两个不同步骤( 或 ),具体取决于是否成功:​​stepA​​​​stepB​​​​stepC​​​​stepA​​

Java配置

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
        .start(stepA())
        .on("*").to(stepB())
        .from(stepA()).on("FAILED").to(stepC())
        .end()
        .build();
}

使用 XML 配置时,转换元素的属性使用简单的 模式匹配方案,以匹配执行 .​​on​​​​ExitStatus​​​​Step​​

使用 java 配置时,该方法使用简单的模式匹配方案来 匹配执行 时产生的结果。​​on()​​​​ExitStatus​​​​Step​​

模式中只允许两个特殊字符:

​​*​​ 匹配零个或多个字符
​​? ​​只匹配一个字符

例如,匹配和 ,而匹配但不匹配 。​​c*t​​​​cat​​​​count​​​​c?t​​​​cat​​​​count​​

虽然 上的转换元素数量没有限制,但如果执行导致元素未涵盖的 ,则 框架引发异常和失败。框架自动订购 从最具体到最不具体的过渡。这意味着,即使订购 在前面的示例中被交换,一个 of 仍然会去 自。​​Step​​​​Step​​​​ExitStatus​​​​Job​​​​stepA​​​​ExitStatus​​​​FAILED​​​​stepC​​
批处理状态与退出状态

为条件流配置 时,了解 和 之间的区别。 是一个枚举 是两者的属性,并且被框架用于 记录 或 的状态。它可以是以下值之一:、 或 。它们中的大多数是不言自明的:是步骤时设置的状态 或作业已成功完成,在失败时设置,依此类推。​​Job​​​​BatchStatus​​​​ExitStatus​​​​BatchStatus​​​​JobExecution​​​​StepExecution​​​​Job​​​​Step​​​​COMPLETED​​​​STARTING​​​​STARTED​​​​STOPPING​​​​STOPPED​​​​FAILED​​​​ABANDONED​​​​UNKNOWN​​​​COMPLETED​​​​FAILED​​

以下示例包含使用 XML 配置时的元素:​​next​​

<next on="FAILED" to="stepB" />

以下示例包含使用 Java 配置时的元素:​​on​​

.from(stepA()).on("FAILED").to(stepB())

乍一看,似乎引用了 它所属的。但是,它实际上引用了 .作为 名称表示,表示 A 完成执行后的状态。​​on​​​​BatchStatus​​​​Step​​​​ExitStatus​​​​Step​​​​ExitStatus​​​​Step​​

更具体地说,使用 XML 配置时,元素显示在 前面的 XML 配置示例引用了 的退出代码。​​next​​​​ExitStatus​​

使用 Java 配置时,前面所示的方法 Java 配置示例引用 的退出代码。​​on()​​​​ExitStatus​​

在英语中,它说:“如果退出代码失败,则转到步骤B”。默认情况下,退出 代码始终与 for 相同,这就是为什么前面的条目 工程。但是,如果退出代码需要不同怎么办?一个很好的例子来自 示例项目中的跳过示例作业:​​BatchStatus​​​​Step​​

下面的示例演示如何在 XML 中使用不同的退出代码:

XML 配置

<step id="step1" parent="s1">
    <end on="FAILED" />
    <next on="COMPLETED WITH SKIPS" to="errorPrint1" />
    <next on="*" to="step2" />
</step>

以下示例演示如何在 Java 中使用不同的退出代码:

Java配置

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
      .start(step1()).on("FAILED").end()
      .from(step1()).on("COMPLETED WITH SKIPS").to(errorPrint1())
      .from(step1()).on("*").to(step2())
      .end()
      .build();
}

​​step1​​有三种可能性:

失败,在这种情况下,作业应失败。Step
成功完成。Step
已成功完成,但退出代码为 。在 在这种情况下,应运行不同的步骤来处理错误。StepCOMPLETED WITH SKIPS

上述配置有效。但是,需要根据以下内容更改退出代码 执行跳过记录的条件,如以下示例所示:

public class SkipCheckingListener extends StepExecutionListenerSupport {
    public ExitStatus afterStep(StepExecution stepExecution) {
        String exitCode = stepExecution.getExitStatus().getExitCode();
        if (!exitCode.equals(ExitStatus.FAILED.getExitCode()) &&
              stepExecution.getSkipCount() > 0) {
            return new ExitStatus("COMPLETED WITH SKIPS");
        }
        else {
            return null;
        }
    }
}

前面的代码是首先检查以确保 成功,然后检查 上的跳过计数是否高于 0. 如果同时满足这两个条件,则返回退出代码为 的新。​​StepExecutionListener​​​​Step​​​​StepExecution​​​​ExitStatus​​​​COMPLETED WITH SKIPS​​

配置停止

在讨论了​ ​批处理状态和退出状态​​之后, 有人可能想知道 和 是如何确定 的 . 虽然这些状态是由执行的代码确定的,但 的状态是根据配置确定的。​​BatchStatus​​​​ExitStatus​​​​Job​​​​Step​​​​Job​​

到目前为止,所有讨论的作业配置都至少有一次决赛 无过渡。​​Step​​

在下面的 XML 示例中,执行后结束:​​step​​​​Job​​

<step id="stepC" parent="s3"/>

在下面的 Java 示例中,执行后,结束:​​step​​​​Job​​

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
        .start(step1())
        .build();
}

如果没有为 定义转换,则 的状态定义为 遵循:​​Step​​​​Job​​

如果以 的结尾,则 和 的 两者都是.StepExitStatusFAILEDBatchStatusExitStatusJobFAILED
否则,和 的 都是 。BatchStatusExitStatusJobCOMPLETED

虽然这种终止批处理作业的方法足以满足某些批处理作业,例如 可能需要简单的顺序步骤作业,自定义的作业停止方案。为 为此,Spring Batch 提供了三个过渡元素来阻止 (在 添加到我们之前讨论的​ ​下一个元素​​)。 这些停止元素中的每一个都停止一个特定的 .是的 请务必注意,停止过渡元素对 中的任何 或 都没有影响。这些元素仅影响 的最终状态。例如,作业中的每个步骤都可能具有 状态为 ,但作业的状态为 。​​Job​​​​Job​​​​BatchStatus​​​​BatchStatus​​​​ExitStatus​​​​Steps​​​​Job​​​​Job​​​​FAILED​​​​COMPLETED​​
一步结束

配置步骤结束指示 停止,并返回 的 。已完成且状态为 无法重新启动的 A (框架抛出 a ).​​Job​​​​BatchStatus​​​​COMPLETED​​​​Job​​​​COMPLETED​​​​JobInstanceAlreadyCompleteException​​

使用 XML 配置时,可以将该元素用于此任务。元素 还允许使用可选属性来自定义 .如果未给出属性,则缺省情况下为 与 .​​end​​​​end​​​​exit-code​​​​ExitStatus​​​​Job​​​​exit-code​​​​ExitStatus​​​​COMPLETED​​​​BatchStatus​​

使用 Java 配置时,该方法用于此任务。方法 还允许使用可选参数来自定义 .如果未提供任何值,则缺省情况下为 与 .​​end​​​​end​​​​exitStatus​​​​ExitStatus​​​​Job​​​​exitStatus​​​​ExitStatus​​​​COMPLETED​​​​BatchStatus​​

请考虑以下方案:如果失败,则 停止并显示 of 和 of ,并且不会运行。 否则,执行将移至 。请注意,如果失败,则 不是 可重新启动(因为状态为 )。​​step2​​​​Job​​​​BatchStatus​​​​COMPLETED​​​​ExitStatus​​​​COMPLETED​​​​step3​​​​step3​​​​step2​​​​Job​​​​COMPLETED​​

以下示例显示了 XML 中的方案:

<step id="step1" parent="s1" next="step2">

<step id="step2" parent="s2">
    <end on="FAILED"/>
    <next on="*" to="step3"/>
</step>

<step id="step3" parent="s3">

以下示例显示了 Java 中的场景:

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
        .start(step1())
        .next(step2())
        .on("FAILED").end()
        .from(step2()).on("*").to(step3())
        .end()
        .build();
}

步骤失败

将步骤配置为在给定点失败会指示 停止,并显示 的 。与 end 不同,a 的失败不会阻止重新启动。​​Job​​​​BatchStatus​​​​FAILED​​​​Job​​​​Job​​

使用 XML 配置时,该元素还允许一个可选属性,该属性可用于自定义 .如果未给出属性,则缺省情况下为 与 .​​fail​​​​exit-code​​​​ExitStatus​​​​Job​​​​exit-code​​​​ExitStatus​​​​FAILED​​​​BatchStatus​​

请考虑以下方案:如果失败,则停止时以 of 和 of 和 not 执行。否则,执行将移至 。此外,如果失败并重新启动,则在 上将再次开始执行。​​step2​​​​Job​​​​BatchStatus​​​​FAILED​​​​ExitStatus​​​​EARLY TERMINATION​​​​step3​​​​step3​​​​step2​​​​Job​​​​step2​​

以下示例显示了 XML 中的方案:

XML 配置

<step id="step1" parent="s1" next="step2">

<step id="step2" parent="s2">
    <fail on="FAILED" exit-code="EARLY TERMINATION"/>
    <next on="*" to="step3"/>
</step>

<step id="step3" parent="s3">

以下示例显示了 Java 中的场景:

Java配置

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
      .start(step1())
      .next(step2()).on("FAILED").fail()
      .from(step2()).on("*").to(step3())
      .end()
      .build();
}

在给定步骤停止作业

将作业配置为在特定步骤处停止会指示 停止,并显示 的 。停止 a 可能会暂时中断处理, 以便操作员可以在重新启动 .​​Job​​​​BatchStatus​​​​STOPPED​​​​Job​​​​Job​​

使用 XML 配置时,元素需要一个指定 重新启动时应继续执行的步骤。​​stop​​​​restart​​​​Job​​

使用 Java 配置时,该方法需要一个属性 指定在重新启动作业时应继续执行的步骤。​​stopAndRestart​​​​restart​​

请考虑以下方案:如果以 完成,则作业 停止。重新启动后,执行将在 开始。​​step1​​​​COMPLETE​​​​step2​​

下面的清单显示了 XML 中的方案:

<step id="step1" parent="s1">
    <stop on="COMPLETED" restart="step2"/>
</step>

<step id="step2" parent="s2"/>

以下示例显示了 Java 中的场景:

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
      .start(step1()).on("COMPLETED").stopAndRestart(step2())
      .end()
      .build();
}

程序化流程决策

在某些情况下,比决定所需的更多信息 下一步要执行的步骤。在这种情况下,可以使用 来协助 在决策中,如以下示例所示:​​ExitStatus​​​​JobExecutionDecider​​

public class MyDecider implements JobExecutionDecider {
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        String status;
        if (someCondition()) {
            status = "FAILED";
        }
        else {
            status = "COMPLETED";
        }
        return new FlowExecutionStatus(status);
    }
}

在以下示例作业配置中,a 指定要用作的决策程序 以及所有过渡:​​decision​​

XML 配置

<job id="job">
    <step id="step1" parent="s1" next="decision" />

    <decision id="decision" decider="decider">
        <next on="FAILED" to="step2" />
        <next on="COMPLETED" to="step3" />
    </decision>

    <step id="step2" parent="s2" next="step3"/>
    <step id="step3" parent="s3" />
</job>
<beans:bean id="decider" class="com.MyDecider"/>

在下面的示例中,传递了实现 使用 Java 配置时直接调用:​​JobExecutionDecider​​​​next​​

Java配置

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
      .start(step1())
      .next(decider()).on("FAILED").to(step2())
      .from(decider()).on("COMPLETED").to(step3())
      .end()
      .build();
}

拆分流

到目前为止,描述的每个场景都涉及一个执行其步骤一个 线性方式的时间。除了这种典型的风格,Spring Batch 还允许 用于使用并行流配置作业。​​Job​​

XML 命名空间允许您使用该元素。如以下示例所示, 该元素包含一个或多个元素,其中整个单独的流可以 被定义。元素还可以包含前面讨论的任何转换 元素,例如属性或 、 或元素。​​split​​​​split​​​​flow​​​​split​​​​next​​​​next​​​​end​​​​fail​​

<split id="split1" next="step4">
    <flow>
        <step id="step1" parent="s1" next="step2"/>
        <step id="step2" parent="s2"/>
    </flow>
    <flow>
        <step id="step3" parent="s3"/>
    </flow>
</split>
<step id="step4" parent="s4"/>

基于 Java 的配置允许您通过提供的构建器配置拆分。作为 以下示例显示,该元素包含一个或多个元素,其中 可以定义整个单独的流。元素还可以包含任何 前面讨论的过渡元素,例如属性或 、 或元素。​​split​​​​flow​​​​split​​​​next​​​​next​​​​end​​​​fail​​

@Bean
public Flow flow1() {
  return new FlowBuilder<SimpleFlow>("flow1")
      .start(step1())
      .next(step2())
      .build();
}

@Bean
public Flow flow2() {
  return new FlowBuilder<SimpleFlow>("flow2")
      .start(step3())
      .build();
}

@Bean
public Job job(Flow flow1, Flow flow2) {
  return this.jobBuilderFactory.get("job")
        .start(flow1)
        .split(new SimpleAsyncTaskExecutor())
        .add(flow2)
        .next(step4())
        .end()
        .build();
}

外部化流定义和作业之间的依赖关系

作业中的部分流可以外部化为单独的 Bean 定义,然后 重复使用。有两种方法可以做到这一点。第一种是将流声明为 引用在其他地方定义的一个。

下面的 XML 示例演示如何将流声明为对定义的流的引用 别处:

XML 配置

<job id="job">
    <flow id="job1.flow1" parent="flow1" next="step3"/>
    <step id="step3" parent="s3"/>
</job>

<flow id="flow1">
    <step id="step1" parent="s1" next="step2"/>
    <step id="step2" parent="s2"/>
</flow>

以下 Java 示例演示如何将流声明为对定义的流的引用 别处:

Java配置

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
        .start(flow1())
        .next(step3())
        .end()
        .build();
}

@Bean
public Flow flow1() {
  return new FlowBuilder<SimpleFlow>("flow1")
      .start(step1())
      .next(step2())
      .build();
}

如前面的示例所示,定义外部流的效果是将外部流中的步骤插入到作业中,就像它们已被声明为内联一样。 这样,多个作业就可以引用同一个模板流,并将这些模板组成不同的逻辑流。 这也是分离各个流程的集成测试的好方法。

外部化流的另一种形式是使用 . A 与 a 类似,但实际上为指定流程中的步骤创建并启动单独的作业执行。​​JobStep​​​​JobStep​​​​FlowStep​​

以下示例展示了 XML 中的 a 示例:​​JobStep​​

XML Configuration

<job id="jobStepJob" restartable="true">
   <step id="jobStepJob.step1">
      <job ref="job" job-launcher="jobLauncher"
          job-parameters-extractor="jobParametersExtractor"/>
   </step>
</job>

<job id="job" restartable="true">...</job>

<bean id="jobParametersExtractor" class="org.spr...DefaultJobParametersExtractor">
   <property name="keys" value="input.file"/>
</bean>

Java配置

@Bean
public Job jobStepJob(JobRepository jobRepository) {
  return new JobBuilder("jobStepJob", jobRepository)
        .start(jobStepJobStep1(null))
        .build();
}

@Bean
public Step jobStepJobStep1(JobLauncher jobLauncher, JobRepository jobRepository) {
  return new StepBuilder("jobStepJobStep1", jobRepository)
        .job(job())
        .launcher(jobLauncher)
        .parametersExtractor(jobParametersExtractor())
        .build();
}

@Bean
public Job job(JobRepository jobRepository) {
  return new JobBuilder("job", jobRepository)
        .start(step1())
        .build();
}

@Bean
public DefaultJobParametersExtractor jobParametersExtractor() {
  DefaultJobParametersExtractor extractor = new DefaultJobParametersExtractor();

  extractor.setKeys(new String[]{"input.file"});

  return extractor;
}

作业参数提取器是一种策略,用于确定如何 转换为 用于运行。这是 当您希望有一些更精细的选项来监视和报告 作业和步骤。使用通常也是对以下问题的良好回答:“我如何 在作业之间创建依赖关系?这是将大型系统分解为的好方法 更小的模块并控制作业流。​​ExecutionContext​​​​Step​​​​JobParameters​​​​Job​​​​JobStep​​​​JobStep​​
和属性的后期绑定​​Job​​​​Step​​

前面显示的 XML 和平面文件示例都使用 Spring 抽象 以获取文件。这是有效的,因为有一个返回 .您可以使用标准 Spring 配置 XML 和平面文件资源 构建:​​Resource​​​​Resource​​​​getFile​​​​java.io.File​​

下面的示例演示 XML 中的后期绑定:

XML 配置

<bean id="flatFileItemReader"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource"
              value="file://outputs/file.txt" />
</bean>

以下示例显示了 Java 中的后期绑定:

Java配置

@Bean
public FlatFileItemReader flatFileItemReader() {
  FlatFileItemReader<Foo> reader = new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource("file://outputs/file.txt"))
      ...
}

前面从指定的文件系统位置加载文件。注意 该绝对位置必须以双斜杠 () 开头。在大多数春天 应用程序,这个解决方案已经足够好了,因为这些资源的名称是 编译时已知。但是,在批处理方案中,文件名可能需要 在运行时确定为作业的参数。这可以使用参数来解决 以读取系统属性。​​Resource​​​​//​​​​-D​​

下面的示例演示如何从 XML 中的属性中读取文件名:

XML 配置

<bean id="flatFileItemReader"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="${input.file.name}" />
</bean>

下面显示了如何从 Java 中的属性读取文件名:

Java配置

@Bean
public FlatFileItemReader flatFileItemReader(@Value("${input.file.name}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource(name))
      ...
}

此解决方案工作所需的只是一个系统参数(例如 )。​​-Dinput.file.name="file://outputs/file.txt"​​

虽然你可以在这里使用,但它不是 如果始终设置系统属性,则为必需,因为在 Spring 中 已经过滤并在系统属性上替换占位符。​​PropertyPlaceholderConfigurer​​​​ResourceEditor​​

通常,在批处理设置中,最好在作业中参数化文件名(而不是通过系统属性)并访问它们 道路。为了实现这一点,Spring Batch 允许各种属性的后期绑定。​​JobParameters​​​​Job​​​​Step​​

下面的示例演示如何在 XML 中参数化文件名:

XML 配置

<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobParameters['input.file.name']}" />
</bean>

以下示例演示如何在 Java 中参数化文件名:

Java配置

@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file.name']}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource(name))
      ...
}

您可以访问 和 级别 同样的方式。​​JobExecution​​​​StepExecution​​​​ExecutionContext​​

下面的示例演示如何访问 XML 中的:​​ExecutionContext​​

XML 配置

<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobExecutionContext['input.file.name']}" />
</bean>

XML 配置

<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="#{stepExecutionContext['input.file.name']}" />
</bean>

以下示例显示了如何在 Java 中访问 :​​ExecutionContext​​

Java配置

@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobExecutionContext['input.file.name']}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource(name))
      ...
}

Java配置

@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{stepExecutionContext['input.file.name']}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource(name))
      ...
}

任何使用后期绑定的 Bean 都必须使用 声明。有关详细信息,请参阅步骤范围​。 Bean 不应是步进范围的。如果步骤中需要后期绑定 定义,该步骤的组件(tasklet、item reader 或 writer 等) 是应该限定范围的那些。​​scope="step"​​​​Step​​

如果您使用 Spring 3.0(或更高版本),则步作用域 Bean 中的表达式位于 Spring 表达式语言,一种功能强大的通用语言,具有许多有趣的功能 特征。为了提供向后兼容性,如果 Spring Batch 检测到存在 旧版本的 Spring,它使用一种不太强大的原生表达式语言和 解析规则略有不同。主要区别在于地图键 上面的例子不需要在 Spring 2.5 中引用,但引用是强制性的 在Spring 3.0 中。
Step Scope

<bean id="flatFileItemReader" scope="step"
      class="org.springframework.batch.item.file.FlatFileItemReader">
    <property name="resource" value="#{jobParameters[input.file.name]}" />
</bean>

Java配置

@StepScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input.file.name]}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource(name))
      ...
}

使用后期绑定需要使用 的范围,因为 bean 在启动之前实际上无法实例化,以便找到属性。 因为默认情况下它不是 Spring 容器的一部分,所以必须通过使用命名空间、显式包含 的 bean 定义或使用注释来显式添加范围。 仅使用其中一种方法。 以下示例使用命名空间:​​Step​​​​Step​​​​batch​​​​StepScope​​​​@EnableBatchProcessing​​​​batch​​

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:batch="http://www.springframework.org/schema/batch"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="...">
<batch:job .../>
...
</beans>

以下示例显式包含 Bean 定义:

<bean class="org.springframework.batch.core.scope.StepScope" />

工作范围

​​Job​​Spring Batch 3.0 中引入的作用域类似于配置中的作用域 但是是上下文的范围,因此这样的 Bean 只有一个实例 每个正在运行的作业。此外,还提供了对引用的后期绑定的支持 使用占位符从 访问。使用此功能,您可以拉豆 作业或作业执行上下文中的属性以及作业参数。​​Step​​​​Job​​​​JobContext​​​​#{…}​​

下面的示例演示在 XML 中绑定到作业范围的示例:

XML 配置

<bean id="..." class="..." scope="job">
    <property name="name" value="#{jobParameters[input]}" />
</bean>

XML 配置

<bean id="..." class="..." scope="job">
    <property name="name" value="#{jobExecutionContext['input.name']}.txt" />
</bean>

以下示例显示了在 Java 中绑定到作业范围的示例:

Java配置

@JobScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input]}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource(name))
      ...
}

Java配置

@JobScope
@Bean
public FlatFileItemReader flatFileItemReader(@Value("#{jobExecutionContext['input.name']}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .name("flatFileItemReader")
      .resource(new FileSystemResource(name))
      ...
}

由于默认情况下它不是 Spring 容器的一部分,因此必须添加范围 显式地,通过使用命名空间,通过显式包含 Bean 定义 作业范围,或使用批注(仅选择一种方法)。 以下示例使用命名空间:​​batch​​​​@EnableBatchProcessing​​​​batch​​

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:batch="http://www.springframework.org/schema/batch"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="...">

<batch:job .../>
...
</beans>

以下示例包含一个显式定义 的 Bean:​​JobScope​​

<bean class="org.springframework.batch.core.scope.JobScope" /> 

在多线程中使用作业范围的 Bean 存在一些实际限制 或分区步骤。Spring 批处理不控制在这些线程中生成的线程 用例,因此无法正确设置它们以使用此类 bean。因此 我们不建议在多线程或分区步骤中使用作业范围的 Bean。
范围界定组件​​ItemStream​​

使用 Java 配置样式定义作业或步骤作用域 Bean 时, Bean 定义方法的返回类型应至少为 。这是必需的 以便 Spring Batch 正确创建实现此接口的代理,因此 按预期通过调用 和方法来履行协定。​​ItemStream​​​​ItemStream​​​​open​​​​update​​​​close​​

建议让这类豆子的 bean 定义方法返回最具体的 已知实现,如以下示例所示:

定义具有最具体返回类型的步骤范围的 Bean文章来源地址https://www.toymoban.com/news/detail-704247.html

@Bean
@StepScope
public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file.name']}") String name) {
  return new FlatFileItemReaderBuilder<Foo>()
      .resource(new FileSystemResource(name))
      // set other properties of the item reader
      .build();
}

到了这里,关于Spring Batch -配置步骤 (XML/Java)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Batch之读数据库—JdbcPagingItemReader(四十一)

            Spring Batch框架提供了对JDBC分页读取支持的组件JdbcPagingItemReader。JdbcPaginItemReader实现ItemReader接口,核心作用是将数据库中记录通过分页的方式转换为Java对象。在JdbcPagingItemReader将数据库记录转换为Java对象是主要有两步工作:首先根据SimpleJdbcTemplate与PagingQueryProvid

    2024年02月16日
    浏览(36)
  • 非常强,批处理框架 Spring Batch 就该这么用!(场景实战)

    概念词就不多说了,我简单地介绍下 , spring batch 是一个 方便使用的 较健全的 批处理 框架。 为什么说是方便使用的,因为这是 基于spring的一个框架,接入简单、易理解、流程分明。 为什么说是较健全的, 因为它提供了往常我们在对大批量数据进行处理时需要考虑到的 日

    2024年02月04日
    浏览(35)
  • Spring Kafka消费模式(single, batch)及确认模式(自动、手动)示例

    Spring Kafka消费消息的模式分为2种模式(对应spring.kafka.listener.type配置): single - 每次消费单条记录 batch - 批量消费消息列表 且每种模式都分为2种提交已消费消息offset的ack模式: 自动确认 手动确认 接下来依次讲解这两种消费模式及其对应的ack模式的示例配置及代码。 本章节

    2023年04月08日
    浏览(38)
  • 【咕咕送书 | 第7期】深入探索Spring Batch:大规模批处理的领航者

    🎬 鸽芷咕 :个人主页  🔥 个人专栏 :《linux深造日志》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! ✅ 参与方式: 关注 博主、 点赞 、 收藏 、 评论 ,任意评论(每人最多评论三次) ⛳️ 本次送书 1~3 本 【 取决于阅读量,阅读量越多,送的越多 】 📆 活动时间

    2024年02月04日
    浏览(51)
  • Spring核心配置步骤-完全基于XML的配置

    Spring框架的核心配置涉及多个方面,包括依赖注入(DI)、面向切面编程(AOP)等。以下是一般情况下配置Spring应用程序的核心步骤: 1. **引入Spring依赖:** 在项目的构建工具(如Maven、Gradle)配置文件中,添加Spring框架的依赖。 2. **创建Spring配置文件:** 创建一个XML文件(通

    2024年02月11日
    浏览(38)
  • Spring CORS 跨域使用与原理(@CrossOrigin注解,Java配置类方式,xml方式)

    出于安全原因,浏览器禁止AJAX调用当前源之外的资源。 跨域资源共享(CORS)是由大多数浏览器实现的W3C规范,它允许您以一种灵活的方式指定授权哪种跨域请求,而不是使用一些不太安全、功能不太强大的hack(如IFrame或JSONP)。 Spring Framework 4.2 GA为CORS提供了一流的开箱即用支持

    2024年02月08日
    浏览(60)
  • Spring boot项目java bean和xml互转

    工作中需要给下游第三方收费系统做数据挡板,由于下游系统使用的是 soap webservice ,里面涉及各种xml跟bean的互转,在此介绍一下使用的方法。 基于springboot搭建webservice的过程将会在下篇博客介绍 这里介绍两种方法. 使用 jackson 进行互转, Spring boot 项目自带的 json 和 bean 的互

    2024年01月19日
    浏览(50)
  • Spring-1-深入理解Spring XML中的依赖注入(DI):简化Java应用程序开发

    前两篇文章我们介绍了什么是Spring,以及Spring的一些核心概念,并且快速快发一个Spring项目,以及详细讲解IOC,今天详细介绍一些DI(依赖注入) 能够配置setter方式注入属性值 能够配置构造方式注入属性值 能够理解什么是自动装配 思考:向一个类中传递数据的方式有几种?(给类

    2024年02月13日
    浏览(50)
  • 【目标检测】epoch、、batch、、batch_size理解

    1 epoch         当一个完整的数据集通过神经网络一次并且返回一次的过程称为一个epoch。 然而,当一个epoch对于计算机太过庞大时,就需要把它分成多个小块。 2 batch         在不能将数据一次性通过神经网络的适合,就需要将数据集分成几个batch。 3 batch_size      

    2024年02月16日
    浏览(32)
  • Spring:xml 配置

    在 Spring 中,配置 bean 实例一般使用 xml 配置 方式或 注解(Annontation) 方式进行配置。 在 xml 配置中分为三种方式,分别为反射模式、工厂方法模式和 Factory Bean 模式。 反射模式 :指通过指定 bean 的 class 属性值来创建对象(最为常用,前面的文章一直使用该模式) 工厂方法

    2024年02月16日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包