重複
RepeatTemplate
批處理就是重複性的操作,既可以是簡單的最佳化,也可以是作業的一部分。為了制定和概括重複操作並提供迭代器框架,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,向呼叫者表明沒有工作剩餘。有些迭代可能會因回撥中正在進行的工作的內在考慮而終止。其他迭代實際上是無限迴圈(就回調而言),並且完成決策委託給外部策略,如前面示例所示。
完成策略
在 RepeatTemplate 中,iterate 方法中迴圈的終止由 CompletionPolicy 決定,它也是 RepeatContext 的工廠。RepeatTemplate 負責使用當前策略建立 RepeatContext,並在迭代的每個階段將其傳遞給 RepeatCallback。在回撥完成其 doInIteration 後,RepeatTemplate 必須呼叫 CompletionPolicy 以要求它更新其狀態(將儲存在 RepeatContext 中)。然後它詢問策略迭代是否完成。
Spring Batch 提供了一些簡單的通用 CompletionPolicy 實現。SimpleCompletionPolicy 允許執行固定次數(RepeatStatus.FINISHED 強制隨時提前完成)。
使用者可能需要實現自己的完成策略以進行更復雜的決策。例如,一個批處理視窗阻止批處理作業在線上系統使用後執行,這將需要一個自定義策略。
異常處理
如果在 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 時,限制會在巢狀迭代中的同級上下文之間保持(例如,步驟內的一組塊)。
監聽器
通常,能夠為跨多個不同迭代的橫切關注點接收額外的回撥非常有用。為此,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,它使用 Spring TaskExecutor 策略執行 RepeatCallback。預設是使用 SynchronousTaskExecutor,其效果是在同一執行緒中執行整個迭代(與普通的 RepeatTemplate 相同)。
宣告式迭代
有時,您知道每次發生時都希望重複一些業務處理。經典的例子是訊息管道的最佳化。如果一批訊息頻繁到達,則處理它們比為每條訊息承擔單獨事務的成本更有效率。Spring Batch 提供了一個 AOP 攔截器,它為此目的將方法呼叫包裝在 RepeatOperations 物件中。RepeatOperationsInterceptor 執行被攔截的方法並根據提供的 RepeatTemplate 中的 CompletionPolicy 進行重複。
-
Java
-
XML
以下示例使用 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;
}
以下示例顯示了使用 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"/>
前面的示例在攔截器內部使用預設的 RepeatTemplate。要更改策略、監聽器和其他詳細資訊,您可以將 RepeatTemplate 例項注入到攔截器中。
如果被攔截方法返回 void,則攔截器始終返回 RepeatStatus.CONTINUABLE(因此如果 CompletionPolicy 沒有有限的終點,則存在無限迴圈的危險)。否則,它返回 RepeatStatus.CONTINUABLE,直到被攔截方法的返回值是 null。此時,它返回 RepeatStatus.FINISHED。因此,目標方法內部的業務邏輯可以透過返回 null 或丟擲由提供的 RepeatTemplate 中的 ExceptionHandler 重新丟擲的異常來表示沒有更多工作要做。