攔截 Step 執行
與 Job 一樣,在 Step 執行期間,使用者可能需要在許多事件中執行某些功能。例如,為了寫入需要頁尾的平面檔案,當 Step 完成時,需要通知 ItemWriter,以便可以寫入頁尾。這可以透過眾多 Step 範圍監聽器之一實現。
你可以透過 listeners 元素將實現 StepListener 擴充套件之一(但不是該介面本身,因為它為空)的任何類應用於步驟。listeners 元素在步驟、任務或塊宣告中有效。我們建議你將監聽器宣告在其功能適用的級別,或者,如果它是多功能的(例如 StepExecutionListener 和 ItemReadListener),則將其宣告在其適用的最細粒度級別。
-
Java
-
XML
以下示例顯示了在 Java 中應用於塊級別的監聽器
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.<String, String>chunk(10).transactionManager(transactionManager)
.reader(reader())
.writer(writer())
.listener(chunkListener())
.build();
}
以下示例顯示了在 XML 中應用於塊級別的監聽器
<step id="step1">
<tasklet>
<chunk reader="reader" writer="writer" commit-interval="10"/>
<listeners>
<listener ref="chunkListener"/>
</listeners>
</tasklet>
</step>
如果使用名稱空間 <step> 元素或其中一個 *StepFactoryBean 工廠,則本身實現 StepListener 介面之一的 ItemReader、ItemWriter 或 ItemProcessor 會自動註冊到 Step。這僅適用於直接注入 Step 的元件。如果監聽器巢狀在另一個元件中,則需要明確註冊它(如前所述,請參閱 註冊 ItemStream 到 Step)。
除了 StepListener 介面之外,還提供了註解來解決相同的問題。普通 Java 物件的方法可以使用這些註解,然後將其轉換為相應的 StepListener 型別。通常還會註解塊元件的自定義實現,例如 ItemReader、ItemWriter 或 Tasklet。XML 解析器會分析 <listener/> 元素的註解,並在構建器中使用 listener 方法進行註冊,因此你只需使用 XML 名稱空間或構建器將監聽器註冊到步驟即可。
StepExecutionListener
StepExecutionListener 表示 Step 執行的最通用監聽器。它允許在 Step 開始之前和結束之後進行通知,無論它是正常結束還是失敗,如下例所示
public interface StepExecutionListener extends StepListener {
void beforeStep(StepExecution stepExecution);
ExitStatus afterStep(StepExecution stepExecution);
}
afterStep 的返回型別是 ExitStatus,以便讓監聽器有機會修改 Step 完成時返回的退出程式碼。
與此介面對應的註解是
-
@BeforeStep -
@AfterStep
ChunkListener
“塊”定義為在事務範圍內處理的項。在每個提交間隔提交事務會提交一個塊。你可以使用 ChunkListener 在塊開始處理之前或塊成功完成之後執行邏輯,如下面的介面定義所示
public interface ChunkListener extends StepListener {
void beforeChunk(ChunkContext context);
void afterChunk(ChunkContext context);
void afterChunkError(ChunkContext context);
}
beforeChunk 方法在事務啟動後但在 ItemReader 開始讀取之前呼叫。相反,afterChunk 在塊提交後呼叫(如果回滾則根本不呼叫)。
與此介面對應的註解是
-
@BeforeChunk -
@AfterChunk -
@AfterChunkError
當沒有塊宣告時,你可以應用 ChunkListener。TaskletStep 負責呼叫 ChunkListener,因此它也適用於非項導向的任務(它在任務之前和之後被呼叫)。
ChunkListener 不設計為丟擲受檢異常。錯誤必須在實現中處理,否則步驟將終止。
ItemReadListener
在前面討論跳過邏輯時,提到記錄跳過的記錄可能很有益,以便以後處理。在讀取錯誤的情況下,這可以透過 ItemReaderListener 完成,如下面的介面定義所示
public interface ItemReadListener<T> extends StepListener {
void beforeRead();
void afterRead(T item);
void onReadError(Exception ex);
}
beforeRead 方法在每次呼叫 ItemReader 上的 read 之前呼叫。afterRead 方法在每次成功呼叫 read 之後呼叫,並傳遞已讀取的項。如果在讀取時發生錯誤,則呼叫 onReadError 方法。提供了遇到的異常,以便可以記錄它。
與此介面對應的註解是
-
@BeforeRead -
@AfterRead -
@OnReadError
ItemProcessListener
與 ItemReadListener 一樣,可以“監聽”項的處理,如下面的介面定義所示
public interface ItemProcessListener<T, S> extends StepListener {
void beforeProcess(T item);
void afterProcess(T item, S result);
void onProcessError(T item, Exception e);
}
beforeProcess 方法在 ItemProcessor 上的 process 之前呼叫,並傳遞要處理的項。afterProcess 方法在項成功處理後呼叫。如果在處理時發生錯誤,則呼叫 onProcessError 方法。提供了遇到的異常和嘗試處理的項,以便可以記錄它們。
與此介面對應的註解是
-
@BeforeProcess -
@AfterProcess -
@OnProcessError
ItemWriteListener
你可以使用 ItemWriteListener “監聽”項的寫入,如下面的介面定義所示
public interface ItemWriteListener<S> extends StepListener {
void beforeWrite(List<? extends S> items);
void afterWrite(List<? extends S> items);
void onWriteError(Exception exception, List<? extends S> items);
}
beforeWrite 方法在 ItemWriter 上的 write 之前呼叫,並傳遞要寫入的項列表。afterWrite 方法在項成功寫入後呼叫,但在提交與塊處理相關的事務之前。如果在寫入時發生錯誤,則呼叫 onWriteError 方法。提供了遇到的異常和嘗試寫入的項,以便可以記錄它們。
與此介面對應的註解是
-
@BeforeWrite -
@AfterWrite -
@OnWriteError
SkipListener
ItemReadListener、ItemProcessListener 和 ItemWriteListener 都提供了錯誤通知機制,但沒有一個會告知你記錄實際上已被跳過。例如,即使項被重試併成功,也會呼叫 onWriteError。因此,有一個單獨的介面用於跟蹤跳過的項,如下面的介面定義所示
public interface SkipListener<T,S> extends StepListener {
void onSkipInRead(Throwable t);
void onSkipInProcess(T item, Throwable t);
void onSkipInWrite(S item, Throwable t);
}
每當在讀取時跳過項時,都會呼叫 onSkipInRead。應該注意的是,回滾可能會導致同一個項被多次註冊為跳過。在寫入時跳過項時,會呼叫 onSkipInWrite。由於該項已成功讀取(未跳過),因此也將其自身作為引數提供。
與此介面對應的註解是
-
@OnSkipInRead -
@OnSkipInWrite -
@OnSkipInProcess