重複

RepeatTemplate

批處理就是重複性的操作,既可以是簡單的最佳化,也可以是作業的一部分。為了制定和概括重複操作並提供迭代器框架,Spring Batch 提供了 RepeatOperations 介面。RepeatOperations 介面的定義如下:

public interface RepeatOperations {

    RepeatStatus iterate(RepeatCallback callback) throws RepeatException;

}

回撥是一個介面,其定義如下,允許您插入一些要重複的業務邏輯:

public interface RepeatCallback {

    RepeatStatus doInIteration(RepeatContext context) throws Exception;

}

回撥會重複執行,直到實現確定迭代應該結束為止。這些介面中的返回值是一個列舉值,可以是 RepeatStatus.CONTINUABLERepeatStatus.FINISHEDRepeatStatus 列舉向重複操作的呼叫者傳達是否有任何工作剩餘的資訊。一般來說,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

RepeatStatus 是 Spring Batch 用來指示處理是否已完成的列舉。它有兩個可能的 RepeatStatus 值:

表 1. RepeatStatus 屬性

描述

CONTINUABLE

還有更多工作要做。

FINISHED

不應再重複。

您可以使用 RepeatStatus 中的 and() 方法將 RepeatStatus 值與邏輯 AND 操作組合。其效果是對可繼續標誌執行邏輯 AND。換句話說,如果任一狀態為 FINISHED,則結果為 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 和一個稍微更靈活的 RethrowOnThresholdExceptionHandlerSimpleLimitExceptionHandler 具有一個限制屬性和一個應該與當前異常進行比較的異常型別。還計算給定型別的所有子類。給定型別的異常將被忽略,直到達到限制,然後它們將被重新丟擲。其他型別的異常總是被重新丟擲。

SimpleLimitExceptionHandler 的一個重要可選屬性是名為 useParent 的布林標誌。它預設為 false,因此限制僅在當前 RepeatContext 中計算。當設定為 true 時,限制會在巢狀迭代中的同級上下文之間保持(例如,步驟內的一組塊)。

監聽器

通常,能夠為跨多個不同迭代的橫切關注點接收額外的回撥非常有用。為此,Spring Batch 提供了 RepeatListener 介面。RepeatTemplate 允許使用者註冊 RepeatListener 實現,並在迭代期間獲得帶有 RepeatContextRepeatStatus(如果可用)的回撥。

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);
}

openclose 回撥在整個迭代之前和之後發生。beforeafteronError 適用於單獨的 RepeatCallback 呼叫。

請注意,當有多個監聽器時,它們在一個列表中,因此存在順序。在這種情況下,openbefore 以相同的順序呼叫,而 afteronErrorclose 以相反的順序呼叫。

並行處理

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 重新丟擲的異常來表示沒有更多工作要做。

© . This site is unofficial and not affiliated with VMware.