• 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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    以下伪代码显示了如何以简化的形式实现​​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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

    尽管 所需的依赖项列表相对较短,但它是一个 极其复杂的类,可能包含许多协作者。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    从父级继承​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    抽象​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    合并列表

    上的一些可配置元素是列表,例如元素。 如果父元素和子元素都声明一个元素,则 子项列表将覆盖父项的列表。允许孩子添加其他 侦听器 对于父级定义的列表,每个列表元素都有一个属性。 如果元素指定 ,则子列表与 父级的,而不是覆盖它。​​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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    提交间隔

    如前所述,步骤读入和写出项目,定期提交 通过使用提供的 .如果为 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    以下示例显示了 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在前面的示例中,每个事务中处理 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以下代码片段显示了 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    前面示例中所示的步骤只能运行一次。尝试再次运行它 导致 被抛出。请注意,默认值为 启动限制为 。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以下代码片段演示如何在 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    配置跳过逻辑

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

    以下 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在前面的示例中,使用了 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    以下 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    通过标识为可跳过的异常类,配置 表示所有内容都是可跳过的。但是,通过“排除”,配置会细化可跳过的列表 异常类为除 之外的所有类。任何排除 如果遇到异常类,则为致命类(即,不会跳过它们)。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    允许对单个项目可以重试的次数限制,并且 “可重试”的异常列表。您可以在重试中找到有关重试工作原理的更多详细信息。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    事务性读取器

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

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

    XML 配置

    <step id="step1">
        <tasklet>
            <chunk reader="itemReader" writer="itemWriter" commit-interval="2"
                   is-reader-transactional-queue="true"/>
        tasklet>
    step>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    以下示例演示如何创建不在 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    交易属性

    您可以使用事务属性来控制 、 和 设置。您可以在 中找到有关设置交易属性的更多信息 春天 核心文档。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以下示例设置 、 和 事务 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    注册时​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    以下示例显示了如何在 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在前面的示例中,不是 ,而是其 代表是。因此,两个委托编写器都必须显式注册为流 以便框架正确处理它们。不需要 显式注册为流,因为它是 的直接属性。步骤 现在可以重新启动,并且读取器和写入器的状态正确保留在 故障事件。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以下示例显示了在 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    本身实现其中一个接口的、 或 会自动注册到 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);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    ​​@BeforeStep​​
    ​​@AfterStep​​
    
    • 1
    • 2

    ​​ChunkListener​​

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

    public interface ChunkListener extends StepListener {
    
        void beforeChunk(ChunkContext context);
        void afterChunk(ChunkContext context);
        void afterChunkError(ChunkContext context);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    与此接口对应的注释是:

      ​​@BeforeChunk​​
        ​​@AfterChunk​​
        ​​@AfterChunkError​​
    
    • 1
    • 2
    • 3

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

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

    public interface ItemReadListener<T> extends StepListener {
    
        void beforeRead();
        void afterRead(T item);
        void onReadError(Exception ex);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    与此接口对应的注释是:

      ​​@BeforeRead​​
        ​​@AfterRead​​
        ​​@OnReadError​​
    
    • 1
    • 2
    • 3

    ​​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);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    与此接口对应的注释是:

     ​​@BeforeProcess​​
        ​​@AfterProcess​​
        ​​@OnProcessError​​
    
    • 1
    • 2
    • 3

    ​​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);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    与此接口对应的注释是:

     ​​@BeforeWrite​​
        ​​@AfterWrite​​
        ​​@OnWriteError​​
    
    • 1
    • 2
    • 3

    ​​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);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    与此接口对应的注释是:

    ​​@OnSkipInRead​​
    ​​@OnSkipInWrite​​
    ​​@OnSkipInProcess​​
    
    • 1
    • 2
    • 3

    跳过侦听器和事务

    最常见的用例之一是注销跳过的项目,因此 另一个批处理过程甚至人工过程可用于评估和修复 导致跳过的问题。因为有很多情况下原始交易 可以回滚,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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    Java配置

    @Bean
    public MethodInvokingTaskletAdapter myTasklet() {
      MethodInvokingTaskletAdapter adapter = new MethodInvokingTaskletAdapter();
    
      adapter.setTargetObject(fooDao());
      adapter.setTargetMethod("updateFoo");
    
      return adapter;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    实现示例​​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");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    前面的实现删除给定目录中的所有文件。它 应该注意的是,该方法只调用一次。剩下的就是 从 引用 。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    以下示例显示了如何从 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    控制步进流

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

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

    Java配置

    @Bean
    public Job job(JobRepository jobRepository) {
      return new JobBuilder("job", jobRepository)
            .start(stepA())
            .next(stepB())
            .next(stepC())
            .build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在上面的场景中,首先运行,因为它是第一个列出的。如果正常完成,则运行,依此类推。但是,如果失败, 整个失败且不执行。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用 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" />
    
    • 1

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

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

    乍一看,似乎引用了 它所属的。但是,它实际上引用了 .作为 名称表示,表示 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    以下示例演示如何在 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ​​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;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    配置停止

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

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

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

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

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

    @Bean
    public Job job(JobRepository jobRepository) {
      return new JobBuilder("job", jobRepository)
            .start(step1())
            .build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果没有为 定义转换,则 的状态定义为 遵循:​​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">
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以下示例显示了 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    步骤失败

    将步骤配置为在给定点失败会指示 停止,并显示 的 。与 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">
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以下示例显示了 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在给定步骤停止作业

    将作业配置为在特定步骤处停止会指示 停止,并显示 的 。停止 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"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    @Bean
    public Job job(JobRepository jobRepository) {
      return new JobBuilder("job", jobRepository)
          .start(step1()).on("COMPLETED").stopAndRestart(step2())
          .end()
          .build();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    程序化流程决策

    在某些情况下,比决定所需的更多信息 下一步要执行的步骤。在这种情况下,可以使用 来协助 在决策中,如以下示例所示:​​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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在以下示例作业配置中,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"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在下面的示例中,传递了实现 使用 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    拆分流

    到目前为止,描述的每个场景都涉及一个执行其步骤一个 线性方式的时间。除了这种典型的风格,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"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    基于 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    作业中的部分流可以外部化为单独的 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    以下 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    外部化流的另一种形式是使用 . 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    作业参数提取器是一种策略,用于确定如何 转换为 用于运行。这是 当您希望有一些更精细的选项来监视和报告 作业和步骤。使用通常也是对以下问题的良好回答:“我如何 在作业之间创建依赖关系?这是将大型系统分解为的好方法 更小的模块并控制作业流。​​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>
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    Java配置

    @Bean
    public FlatFileItemReader flatFileItemReader() {
      FlatFileItemReader<Foo> reader = new FlatFileItemReaderBuilder<Foo>()
          .name("flatFileItemReader")
          .resource(new FileSystemResource("file://outputs/file.txt"))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

    XML 配置

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

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

    Java配置

    @Bean
    public FlatFileItemReader flatFileItemReader(@Value("${input.file.name}") String name) {
      return new FlatFileItemReaderBuilder<Foo>()
          .name("flatFileItemReader")
          .resource(new FileSystemResource(name))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此解决方案工作所需的只是一个系统参数(例如 )。​​-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>
    
    • 1
    • 2
    • 3
    • 4

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

    Java配置

    @StepScope
    @Bean
    public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters['input.file.name']}") String name) {
      return new FlatFileItemReaderBuilder<Foo>()
          .name("flatFileItemReader")
          .resource(new FileSystemResource(name))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    您可以访问 和 级别 同样的方式。​​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>
    
    • 1
    • 2
    • 3
    • 4

    XML 配置

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

    以下示例显示了如何在 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))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Java配置

    @StepScope
    @Bean
    public FlatFileItemReader flatFileItemReader(@Value("#{stepExecutionContext['input.file.name']}") String name) {
      return new FlatFileItemReaderBuilder<Foo>()
          .name("flatFileItemReader")
          .resource(new FileSystemResource(name))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    任何使用后期绑定的 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>
    
    • 1
    • 2
    • 3
    • 4

    Java配置

    @StepScope
    @Bean
    public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input.file.name]}") String name) {
      return new FlatFileItemReaderBuilder<Foo>()
          .name("flatFileItemReader")
          .resource(new FileSystemResource(name))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    使用后期绑定需要使用 的范围,因为 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

    工作范围

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

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

    XML 配置

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

    XML 配置

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

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

    Java配置

    @JobScope
    @Bean
    public FlatFileItemReader flatFileItemReader(@Value("#{jobParameters[input]}") String name) {
      return new FlatFileItemReaderBuilder<Foo>()
          .name("flatFileItemReader")
          .resource(new FileSystemResource(name))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    Java配置

    @JobScope
    @Bean
    public FlatFileItemReader flatFileItemReader(@Value("#{jobExecutionContext['input.name']}") String name) {
      return new FlatFileItemReaderBuilder<Foo>()
          .name("flatFileItemReader")
          .resource(new FileSystemResource(name))
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    由于默认情况下它不是 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

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

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

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

    定义具有最具体返回类型的步骤范围的 Bean

    @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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    Springcloud的学习笔记(一)
    再探快速排序 → 递进式演进,是否更容易理解?
    设计模式-10组合模式(组合模式设计模式)详解
    Oracle-通过(RESTORE/RECOVER FROM SERVICE)方式搭建DataGuard
    vulnhub之momentum
    mysql全文索引
    2022 Android 高级进阶学习资料与高频精选面试题精讲(圆梦大厂)
    python最优化算法实战---线性规划之内点法
    通俗介绍人工智能是什么
    Python垃圾回收
  • 原文地址:https://blog.csdn.net/ryuenkyo/article/details/132715793