什麼是Spring Batch
Spring Batch是Spring 的一個子項目,是一款基於Spring的企業批處理框架,是一個輕量級的、全面的批處理框架。
Spring Batch提供了可重用的功能,不僅提供了統一的讀寫接口、豐富的任務處理方式、靈活的事務管理以及併發處理,同時還支持日誌、監控、任務重啓玉跳過等特性。
爲什麼要使用Spring Batch以及應用的場景
- 爲什麼要使用
Spring Batch是基於Spring開發的很容易上手
Spring Batch不是一個調度框架,因爲它已經有非常好的企業級調度框架包括Quartz等,它只注重任務處理的相關問題,如執行任務、事務、併發等,而不是提供調度功能 - 應用的場景
- 週期提交批處理任務
- 同時批處理任務:並非處理一個任務
- 分階段的企業消息驅動處理
- 高併發批處理
- 失敗後的手動或定時重啓
- 按順序處理任務依賴(使用工作流驅動的批處理插件)
- 部分處理:跳過記錄(例如:回滾)
- 全批次事務:因爲可能有小數據量的批處理或存在存儲過程/腳本
- 批處理的特點
- 數據量大
- 整個過程全部自動化,並預留一定接口進行自定義配置
- 這樣的應用通常是週期性運行,比如按日、周、月運行
- 對數據處理的準確性要求高,並且需要容錯機制、回滾機制、完善的日誌監控等
Spring Batch的處理原則
1. 儘量使用公用模塊
2. 儘量簡化操作,不要有複雜的業務邏輯,更不要處理一條數據還要調用外部接口進行數據加工
3. 儘可能少的IO操作
4. 同一個批處理文件不要處理兩次
5. 儘可能壓力測試
Spring Batch的結構
Spring Batch分三層:應用層、核心層和基礎架構層
應用層: 開發人員使用Spring Batch編寫的所有批處理任務代碼
核心層: 包含加載和控制批處理作業所需的核心類,Job,Step等類的實現
基礎架構層: 包含統用的讀寫器和重試模塊
Spring batch框架有4個主要組件:JobLauncher、Job、Step和JobRepository。
1)JobLauncher(任務啓動器):通過它啓動任務,可以理解爲程序的入口。
2)Job(任務):一個具體的任務。
3)Step(步驟):一個具體的執行步驟,一個Job中可以有多個Step。
4)JobRepository(任務倉庫):存儲數據的倉庫,在任務執行的時候,需要用它來記錄任務狀態信息,可以看做是一個數據庫的接口。
JobLauncher啓動Job,Job可以有多個Step組合,每個Step有開發者自己編寫
每一個Step對應一個ItemReader、ItemProcessor和ItemWriter
job : 任務
一個job可以由一個或多個step組成,通過JobBuilderFactory實例創建Bean,使用next指向下一個step;
flow:
1.是多個step的集合;
2.可以被多個Job複用;
3.由flowBuilder來創建的;
split:
實現併發執行;
批處理框架簡單抽象成:讀取數據、處理數據、寫數據
Spring Batch提供了三個接口: ItemReader、ItemProcessor、ItemWriter
JobRepository是記錄Job、Step和發起Job的執行信息
Spring Batch的核心概念
-
什麼是JobLauncher
JobLauncher是任務啓動器,該接口只有一個run方法
public interface JobLauncher { public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException; }
除了傳入Job對象外,還需要傳入JobParameters對象,通過JobLauncher可以在java程序中調用批處理任務,也可以通過命令行或者其他框架(如定時調度框架Quartz、Web後臺框架Spring MVC)中調用批處理任務
-
什麼是JOB
Job是一個封裝整個批處理過程的概念,體現在代碼中是最上層的一個接口
Job的實現類主要有兩種:一個是simplejob,另一個是flowjob
一個Job是我們運行的基本單位,它內部由Step組成,Job實質上是Step的一個容器,@Bean public Job footballJob(){ return jobBuilderFactory.get("footballJob") .start(firstStep()) .next(secondStep()) .build(); } 配置的意思是:首先給Job起一個名字footballJob,接着指定這個Job的兩個Step(有幾個Step指定幾個,也可以靈活指定),他們分別由方法firstStep()、secondStep()實現
-
什麼是JobInstance
JobInstance指的是邏輯單元的概念,考慮一個批作業,不僅僅執行一次,所以對每個作業的運行必須單獨邏輯的JobInstance跟蹤,而且每個JobInstance可以多個執行,並且在給定時間內相同參數的同一個JobInstance只能有一個能運行。
JobInstance的定義與要加載的數據完全沒有關係
-
什麼是JobParameters
同一個Job每天運行一次的話,每天也就都有一個JobInstance,但是如何區分JobInstance呢?那麼就是JobParameters
JobParameters對象包含一組用於啓動批處理作業的參數,它在運行期間用於識別或者用作參考數據。
JobInstance =Job + JobParameters
-
什麼是JobExecution
JobExecution作爲一個Job一次執行任務的上下文,因爲Job的一個JobInstance有可能失敗而多次執行,這樣就需要一個上下文來管理同一個JobInstance的多次執行,一次執行有可能失敗或成功結束,只有JobExecution執行成功JobInstance才被認爲是完成了。
-
什麼是Step
Step是一個領域對象,它體現了批處理作業的獨立的、連續的階段。一個Step可以簡單也可以複雜,一個簡單的步驟可能會將數據從文件加載到數據庫中,只需要很少或根本不需要代碼,更復雜的步驟可能有作爲處理一部分應用的複雜業務規則。與Job一樣,Step也有獨立的StepExecution存儲每一個Step的執行信息。
-
什麼是StepExecution
StepExecution表示一次執行Step,每次運行一個Step時都會創建一個新的StepExecution,類似與JobExecution,但是某個步驟可能由於其之前的步驟失敗而無法執行,且僅當Step實際啓動時纔會創建StepExecution。
StepExecution 用來表示每一個step 的執行。每個StepExecution都包含對其相應step和與JobExecution以及事務相關數據的引用,比如提交和回滾計數以及開始和結束時間。此外,每個步驟執行都包含一個ExecutionContext,它包含開發人員在批處理運行期間需要持久化的任何數據,例如重新啓動所需的統計信息或狀態信息。
-
什麼是ExecutionContext
ExecutionContext即每一個StepExecution 的執行環境。它包含一系列的鍵值對。我們可以用如下代碼獲取ExecutionContext
ExecutionContext ecStep = stepExecution.getExecutionContext(); ExecutionContext ecJob = jobExecution.getExecutionContext();
-
什麼是JobRepository
JobRepository是一個用於將上述job,step等概念進行持久化的一個類。 它同時給Job和Step以及下文會提到的JobLauncher實現提供CRUD操作。 首次啓動Job時,將從repository中獲取JobExecution,並且在執行批處理的過程中,StepExecution和JobExecution將被存儲到repository當中。
@EnableBatchProcessing註解可以爲JobRepository提供自動配置。
-
什麼是JobLauncher
JobLauncher這個接口的功能非常簡單,它是用於啓動指定了JobParameters的Job,爲什麼這裏要強調指定了JobParameter,原因jobparameter和job一起才能組成一次job的執行
public interface JobLauncher { public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException; }
-
什麼是Item Reader
ItemReader是一個讀數據的抽象,它的功能是爲每一個Step提供數據輸入。 當ItemReader以及讀完所有數據時,它會返回null來告訴後續操作數據已經讀完。Spring Batch爲ItemReader提供了非常多的有用的實現類,比如JdbcPagingItemReader,JdbcCursorItemReader等等。
ItemReader包括各種類型的數據庫,文件,數據流,等等JdbcPagingItemReader必須指定一個PagingQueryProvider,負責提供SQL查詢語句來按分頁返回數據
下面是一個JdbcCursorItemReader的例子代碼: private JdbcCursorItemReader<Map<String, Object>> buildItemReader(final DataSource dataSource, String tableName, String tenant) { JdbcCursorItemReader<Map<String, Object>> itemReader = new JdbcCursorItemReader<>(); itemReader.setDataSource(dataSource); itemReader.setSql("sql here"); itemReader.setRowMapper(new RowMapper()); return itemReader; }
-
什麼是Item Writer
ItemReader是讀數據的一個抽象,那麼ItemWriter自然就是一個寫數據的抽象,它是爲每一個step提供數據寫出的功能。寫的單位是可以配置的,我們可以一次寫一條數據,也可以一次寫一個chunk的數據,關於chunk下文會有專門的介紹。ItemWriter對於讀入的數據是不能做任何操作的。
-
什麼是Item Processor
ItemReader是讀數據的一個抽象,那麼ItemWriter自然就是一個寫數據的抽象,它是爲每一個step提供數據寫出的功能。寫的單位是可以配置的,我們可以一次寫一條數據,也可以一次寫一個chunk的數據,關於chunk下文會有專門的介紹。ItemWriter對於讀入的數據是不能做任何操作的。
-
什麼是Chunk
由於我們一次batch的任務可能會有很多的數據讀寫操作,因此一條一條的處理並向數據庫提交的話效率不會很高,因此spring batch提供了chunk這個概念,我們可以設定一個chunk size,spring batch 將一條一條處理數據,但不提交到數據庫,只有當處理的數據數量達到chunk size設定的值得時候,才一起去commit.
@Bean public Job footballJob(){ return jobBuilderFactory.get("footballJob") .start(Step1()) .build(); } @Bean public Step Step1() { return stepBuilderFactory.get("Step1") .chunk(10) .reader(itemReader()) .writer(itemWriter()) .build(); } 在上面這個step裏面,chunk size被設爲了10,當ItemReader讀的數據數量達到10的時候, 這一批次的數據就一起被傳到itemWriter,同時transaction被提交。
Tasklet 與chunk 的區別:
Tasklet 意味着在step中執行單個任務,job有多個step按一定順序組成,每個步驟應該執行一個具體任務。
我們的job有三個步驟:
a.從輸入csv文件讀
b.對每個輸入行數據計算年齡
c.寫姓名和年齡至輸出csv文件Chunk 方法該方法基於數據塊(一部分數據)執行。也就是說,其不是一次讀、處理和寫所有行,而是一次僅讀、處理、寫固定數量記錄。然後重複循環執行直到讀不到數據爲止。
因此,此流程與上面有些差異:
while 有數據:
do X 行數據
讀一行
處理一行
寫 X 行數據Tasklet 與chunk 總結:
兩者差異顯示了各自適用場景。tasklet更適合一個步驟到另一個步驟場景。chunk提供簡單解決方案:實現處理分頁讀,或我們不想在內存中保留大量數據場景。
Spring Batch小案例
Spring Batch完整入門實踐
Spring Batch 入門級示例教程
參考文檔
Spring Batch參考文檔中文版
spring batch 理解、特點、使用場景、結構 簡單介紹
Spring Batch 文檔和手冊(中文)