SpringBatch从入门到放弃005- 健壮配置之跳过

在许多情况下,处理过程中遇到的错误不应导致Step失败,但应该跳过。这通常是一个必须由了解数据本身及其含义的人做出的决定。例如,财务数据可能无法跳过,因为它会导致资金转移,这需要完全准确。另一方面,加载供应商列表可能允许跳过。如果由于格式不正确或缺少必要信息而未加载供应商,则可能没有问题。通常,这些跳过的记录也会被记录下来,上一节我们在讨论 SkipListener的时候已经知道。

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 配置一个跳过:

  @Bean
  public Step step1() {
      return this.stepBuilderFactory.get("step1")
                  .<String, String>chunk(10)
                  .reader(flatFileItemReader())
                  .writer(itemWriter())
                  .faultTolerant()
                  .skipLimit(10)
                  .skip(FlatFileParseException.class)
                  .build();
}

上边我对FlatFileParseException异常设置了10次跳过,这个限制是 Reader/Processor/Writer 分别进行计数,当其中一个达到第11次的时候,就会直接抛出这个FlatFileParseException异常。

但是上边的例子有个问题就是只跳过FlatFileParseException异常,其他所有的异常都会被标记为失败。在某些情况下,这可能是正确的行为。但是,在其他情况下,可能更容易识别哪些异常应导致失败并跳过其他所有内容。在 Spring Batch 中提供了include 和 exclude(Java配置为skip和noSkip方法调用)来实现这种需求:

   <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 配置:

@Bean
  public Step step1() {
      return this.stepBuilderFactory.get("step1")
                  .<String, String>chunk(10)
                  .reader(flatFileItemReader())
                  .writer(itemWriter())
                  .faultTolerant()
                  .skipLimit(10)
                  .skip(Exception.class)
                  .noSkip(FileNotFoundException.class)
                  .build();
}

这个例子是将java.lang.Exception标识为可跳过的异常类,但是,通过'exclude'(noSkip) 将 java.io.FileNotFoundException异常排除。这就是说这个 Batch 跳过除java.io.FileNotFoundException之外的所有异常,如果遇到java.io.FileNotFoundException异常则提示 Batch 失败。

除了通过include/exclude 来配置跳过之外,Batch 还提供了一种自由度更高的配置,跳过策略(SkipPolicy),定义接口如下:

public interface SkipPolicy {
    boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException;
}

Spring Batch 提供默认实现类如下:

下边我们就通过源码来看看具看这些实现类都是实现了什么策略:

AlwaysSkipItemSkipPolicy

我们先来看AlwaysSkipItemSkipPolicy的源码,发现是直接返回了 True 也就是,无论发生什么异常,都会被跳过。

public class AlwaysSkipItemSkipPolicy implements SkipPolicy {

    @Override
    public boolean shouldSkip(Throwable t, int skipCount) {
        return true;
    }

}

CompositeSkipPolicy

同样我们打开CompositeSkipPolicy的源码,可以发现CompositeSkipPolicy是一种组合的跳过策略,同时我们可以发现,对于组合策略,只要有一个满足跳过条件,整个策略都是跳过的。

public class CompositeSkipPolicy implements SkipPolicy {
    private SkipPolicy[] skipPolicies;
    
    @Override
    public boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException {
        for (SkipPolicy policy : skipPolicies) {
            if (policy.shouldSkip(t, skipCount)) {
                return true;
            }
        }
        return false;
    }
}

ExceptionClassifierSkipPolicy

分析 ExceptionClassifierSkipPolicy的源码,我们发现ExceptionClassifierSkipPolicy会根据当前线程中的 SkipPolicy 来设置跳过的策略。

public class ExceptionClassifierSkipPolicy implements SkipPolicy {
    private SubclassClassifier<Throwable, SkipPolicy> classifier;

    @Override
    public boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException {
        return classifier.classify(t).shouldSkip(t, skipCount);
    }

}

LimitCheckingItemSkipPolicy

可以设置跳过次数的跳过策略,也是 Spring Batch 的默认策略。

public class LimitCheckingItemSkipPolicy implements SkipPolicy {
    private int skipLimit;

    @Override
    public boolean shouldSkip(Throwable t, int skipCount) {
        if (skippableExceptionClassifier.classify(t)) {
            if (skipCount < skipLimit) {
                return true;
            }
            else {
                throw new SkipLimitExceededException(skipLimit, t);
            }
        }
        else {
            return false;
        }
    }
}

NeverSkipItemSkipPolicy

和AlwaysSkipItemSkipPolicy正好相反,无论发生任何异常,都不会被跳过。

public class NeverSkipItemSkipPolicy implements SkipPolicy{
    @Override
    public boolean shouldSkip(Throwable t, int skipCount) {
        return false;
    }
}

记录被跳过之后需要记录掉过的记录,这个时候就需要我们上一节说的 SkipListener 来实现,不熟悉的同学不妨再回头去看看。

猜你喜欢

转载自www.cnblogs.com/ckp-henu/p/springbatch-cong-ru-men-dao-fang-qi005-jian-zhuang.html