SpringBatch从入门到精通-9 重复处理【掘金日新计划】

538 阅读7分钟

持续创作,加速成长,6月更文活动来啦!| 掘金·日新计划

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第18天,点击查看活动详情

SpringBatch从入门到精通-1【掘金日新计划】

SpringBatch从入门到精通-2-StepScope作用域和用法【掘金日新计划】

SpringBatch从入门到精通-3-并行处理【掘金日新计划】

SpringBatch从入门到精通-3.2-并行处理-远程分区【掘金日新计划】

SpringBatch从入门到精通-3.3-并行处理-远程分区(消息聚合)【掘金日新计划】

SpringBatch从入门到精通-4 监控和指标【掘金日新计划】

SpringBatch从入门到精通-4.2 监控和指标-原理【掘金日新计划】

SpringBatch从入门到精通-5 数据源配置相关【掘金日新计划】

SpringBatch从入门到精通-5.2 数据源配置相关-原理【掘金日新计划】

SpringBatch从入门到精通-6 读和写处理【掘金日新计划】

SpringBatch从入门到精通-6.1 读和写处理-实战【掘金日新计划】

SpringBatch从入门到精通-6.2 读和写处理-实战2【掘金日新计划】

SpringBatch从入门到精通-6.3 读和写处理-实战3【掘金日新计划】

SpringBatch从入门到精通-6.4 读和写处理-实战4【掘金日新计划】

SpringBatch从入门到精通-7 常见的批处理的一些模式【掘金日新计划】

SpringBatch从入门到精通-8 数据处理【掘金日新计划】

重复模板

批处理是关于重复操作的,可以作为简单的优化,也可以作为工作的一部分。为了对重复进行策略化和概括,并提供相当于迭代器框架的内容,Spring Batch 提供了RepeatOperations接口。RepeatOperations接口定义如下:

public interface RepeatOperations {
​
    RepeatStatus iterate(RepeatCallback callback) throws RepeatException;
​
}

回调是一个接口,如以下定义所示,可让您插入一些要重复的业务逻辑:

public interface RepeatCallback {
​
    RepeatStatus doInIteration(RepeatContext context) throws Exception;
​
}

回调被重复执行,直到实现确定迭代应该结束。这些接口中的返回值是一个枚举,可以是RepeatStatus.CONTINUABLE或RepeatStatus.FINISHED。枚举向重复操作的RepeatStatus 调用者传达有关是否还有更多工作要做的信息。一般来说,实现RepeatOperations 应该检查RepeatStatus并使用它作为结束迭代的决定的一部分。任何希望向调用者发出没有更多工作要做的信号的回调都可以返回RepeatStatus.FINISHED。

最简单的通用实现RepeatOperations是RepeatTemplate,如以下示例所示:

RepeatTemplate template = new RepeatTemplate();
​
template.setCompletionPolicy(new SimpleCompletionPolicy(2));
​
template.iterate(new RepeatCallback() {
​
    public RepeatStatus doInIteration(RepeatContext context) {
        // Do stuff in batch...
        return RepeatStatus.CONTINUABLE;
    }
​
});

在前面的示例中,我们返回RepeatStatus.CONTINUABLE,以表明还有更多工作要做。回调也可以返回RepeatStatus.FINISHED, 向调用者发出没有更多工作要做的信号。某些迭代可以通过回调中正在完成的工作所固有的考虑来终止。就回调而言,其他实际上是无限循环,并且完成决策被委托给外部策略,如前面示例中所示。

重复上下文repeatContext

RepeatCallback的方法参数是 RepeatContext。许多回调忽略上下文。但是,如果需要,它可以用作属性包来存储迭代期间的瞬态数据。方法返回后iterate,上下文不再存在。

如果正在进行嵌套迭代,则 RepeatContext具有父上下文。父上下文有时可用于存储需要在调用之间共享的数据iterate。例如,如果您想计算迭代中事件的发生次数并在后续调用中记住它,就会出现这种情况。

重复状态

RepeatStatus是 Spring Batch 用来指示处理是否完成的枚举。它有两个可能的RepeatStatus值,如下表所述:

*值描述
CONTINUABLE还有更多工作要做。
FINISHED不应再发生重复。

RepeatStatus也可以使用 and()方法将值与逻辑 AND 运算组合RepeatStatus。这样做的效果是对可连续标志进行逻辑与。换句话说,如果任一状态为FINISHED,则结果为 FINISHED。

完成政策CompletionPolicy

在 内部RepeatTemplate,方法中循环的终止iterate是由CompletionPolicy 决定的,它也是 RepeatContext的工厂。有 RepeatTemplate责任使用当前策略来创建 RepeatContext并将其传递给RepeatCallback迭代的每个阶段。回调完成后doInIteration,RepeatTemplate必须调用 以CompletionPolicy要求它更新其状态(将存储在 中 RepeatContext)。然后它询问策略迭代是否完成。

Spring Batch 提供了一些简单的通用实现CompletionPolicy。 SimpleCompletionPolicy允许执行最多固定次数( RepeatStatus.FINISHED随时强制提前完成)。

用户可能需要为更复杂的决策实施自己的完成策略。例如,在使用在线系统后阻止批处理作业执行的批处理窗口将需要自定义策略。

异常处理

如果在 a 中抛出异常RepeatCallback,则RepeatTemplate返回 ExceptionHandler,它可以决定是否重新抛出异常。

以下清单显示了ExceptionHandler接口定义:

public interface ExceptionHandler {
​
    void handleException(RepeatContext context, Throwable throwable)
        throws Throwable;
​
}

一个常见的用例是计算给定类型的异常数量,并在达到限制时失败。为此,Spring Batch 提供了 SimpleLimitExceptionHandler一个更灵活的 RethrowOnThresholdExceptionHandler. 有SimpleLimitExceptionHandler一个限制属性和一个应该与当前异常进行比较的异常类型。所提供类型的所有子类也被计算在内。给定类型的异常将被忽略,直到达到限制,然后重新抛出它们。其他类型的异常总是被重新抛出。

的一个重要的可选属性SimpleLimitExceptionHandler是名为 的布尔标志useParent。默认情况false下,因此限制仅在当前RepeatContext. 当设置为true时,限制在嵌套迭代中跨同级上下文保持(例如步骤中的一组块)。

Listeners

通常,能够在许多不同的迭代中为横切关注点接收额外的回调是很有用的。为此,Spring Batch 提供了 RepeatListener接口。RepeatTemplate允许用户注册实现,并在 迭代期间向RepeatListener 他们提供回调RepeatContext以及可用的地方。RepeatStatus

RepeatListener接口定义如下:

public interface RepeatListener {
    void before(RepeatContext context);
    void after(RepeatContext context, RepeatStatus result);
    void open(RepeatContext context);
    void onError(RepeatContext context, Throwable e);
    void close(RepeatContext context);
}

和回调在整个迭代之前和之后出现open。, , 并应用于单个呼叫。closebeforeafteronErrorRepeatCallback

请注意,当有多个侦听器时,它们在一个列表中,因此有一个顺序。在这种情况下,open和before以相同的顺序调用,而after, onError和close以相反的顺序调用。

并行处理

RepeatOperations的实现不限于顺序执行回调。一些实现能够并行执行它们的回调是非常重要的。为此,Spring Batch 提供了 TaskExecutorRepeatTemplate,它使用 SpringTaskExecutor策略来运行 RepeatCallback. 默认是使用 SynchronousTaskExecutor,它具有在同一个线程中执行整个迭代的效果(与 normal 相同 RepeatTemplate)。

声明式迭代

有时,您知道每次发生时都想重复某些业务处理。典型的例子是消息管道的优化。如果消息频繁到达,则处理一批消息比为每条消息承担单独事务的成本更有效。RepeatOperationsSpring Batch 提供了一个 AOP 拦截器,它为此目的将方法调用包装在对象中。执行拦截的RepeatOperationsInterceptor方法并根据CompletionPolicy提供的RepeatTemplate.

下面的例子演示了使用 Java 配置来重复一个服务调用到一个被调用的方法processMessage:

@Bean
public MyService myService() {
    ProxyFactory factory = new ProxyFactory(RepeatOperations.class.getClassLoader());
    factory.setInterfaces(MyService.class);
    factory.setTarget(new MyService());
​
    MyService service = (MyService) factory.getProxy();
    JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
    pointcut.setPatterns(".*processMessage.*");
​
    RepeatOperationsInterceptor interceptor = new RepeatOperationsInterceptor();
​
    ((Advised) service).addAdvisor(new DefaultPointcutAdvisor(pointcut, interceptor));
​
    return service;
}

前面的示例RepeatTemplate在拦截器中使用了默认值。要更改策略、侦听器和其他详细信息,您可以将 的实例 RepeatTemplate注入拦截器。

如果被拦截的方法返回void,那么拦截器总是返回 (因此如果没有有限的端点RepeatStatus.CONTINUABLE,则存在无限循环的危险 )。CompletionPolicy否则,它会返回, RepeatStatus.CONTINUABLE直到被拦截方法的返回值为null,此时它返回RepeatStatus.FINISHED。因此,目标方法中的业务逻辑可以通过返回null 或抛出由ExceptionHandler提供的 RepeatTemplate.

代码位置: github.com/jackssybin/…