重复
重复模板
批处理是关于重复操作的,可以作为简单的优化,也可以作为工作的一部分。为了对重复进行策略化和概括,并提供相当于迭代器框架的内容,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
, 向调用者发出没有更多工作要做的信号。某些迭代可以通过回调中正在完成的工作所固有的考虑来终止。就回调而言,其他实际上是无限循环,并且完成决策被委托给外部策略,如前面示例中所示的情况。
完成政策
在 a 内部RepeatTemplate
,方法中循环的终止iterate
是由 a 决定的CompletionPolicy
,它也是RepeatContext
. 有
RepeatTemplate
责任使用当前策略来创建 a
RepeatContext
并将其传递给RepeatCallback
迭代的每个阶段。回调完成后doInIteration
,RepeatTemplate
必须调用 以CompletionPolicy
要求它更新其状态(将存储在 中
RepeatContext
)。然后它询问策略迭代是否完成。
Spring Batch 提供了一些简单的通用实现CompletionPolicy
。
SimpleCompletionPolicy
允许执行最多固定次数(
RepeatStatus.FINISHED
随时强制提前完成)。
用户可能需要为更复杂的决策实施自己的完成策略。例如,一旦在线系统在使用中,阻止批处理作业执行的批处理窗口将需要自定义策略。
异常处理
如果在 a 中抛出异常RepeatCallback
,则RepeatTemplate
咨询 an ExceptionHandler
,它可以决定是否重新抛出异常。
以下清单显示了ExceptionHandler
接口定义:
public interface ExceptionHandler {
void handleException(RepeatContext context, Throwable throwable)
throws Throwable;
}
一个常见的用例是计算给定类型的异常数量,并在达到限制时失败。为此,Spring Batch 提供了
SimpleLimitExceptionHandler
一个更灵活的
RethrowOnThresholdExceptionHandler
. 有SimpleLimitExceptionHandler
一个限制属性和一个应该与当前异常进行比较的异常类型。所提供类型的所有子类也被计算在内。给定类型的异常将被忽略,直到达到限制,然后重新抛出它们。其他类型的异常总是被重新抛出。
的一个重要的可选属性SimpleLimitExceptionHandler
是名为 的布尔标志useParent
。默认情况false
下,因此限制仅在当前RepeatContext
. 当设置为true
时,限制在嵌套迭代中跨同级上下文保持(例如步骤中的一组块)。
听众
通常,能够在许多不同的迭代中为横切关注点接收额外的回调是很有用的。为此,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
。,
, 并应用于单个呼叫。close
before
after
onError
RepeatCallback
请注意,当有多个侦听器时,它们在一个列表中,因此有一个顺序。在这种情况下,open
和before
以相同的顺序调用,而after
,
onError
和close
以相反的顺序调用。
并行处理
的实现RepeatOperations
不限于顺序执行回调。一些实现能够并行执行它们的回调是非常重要的。为此,Spring Batch 提供了
TaskExecutorRepeatTemplate
,它使用 SpringTaskExecutor
策略来运行
RepeatCallback
. 默认是使用 a SynchronousTaskExecutor
,它具有在同一个线程中执行整个迭代的效果(与 normal 相同
RepeatTemplate
)。
声明式迭代
有时,您知道每次发生时都想重复某些业务处理。典型的例子是消息管道的优化。如果消息频繁到达,则处理一批消息比为每条消息承担单独事务的成本更有效。RepeatOperations
Spring Batch 提供了一个 AOP 拦截器,它为此目的将方法调用包装在对象中。执行拦截的RepeatOperationsInterceptor
方法并根据CompletionPolicy
提供的RepeatTemplate
.
以下示例显示了使用 Spring AOP 命名空间重复对所调用方法的服务调用的声明性迭代processMessage
(有关如何配置 AOP 拦截器的更多详细信息,请参阅 Spring 用户指南):
<aop:config>
<aop:pointcut id="transactional"
expression="execution(* com..*Service.processMessage(..))" />
<aop:advisor pointcut-ref="transactional"
advice-ref="retryAdvice" order="-1"/>
</aop:config>
<bean id="retryAdvice" class="org.spr...RepeatOperationsInterceptor"/>
下面的例子演示了使用 Java 配置来重复对被调用方法的服务调用processMessage
(有关如何配置 AOP 拦截器的更多详细信息,请参阅 Spring 用户指南):
@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
.