Spring -batch
SpringBatch從入門到放棄002- 核心概念1
上一篇我們通過一個例子簡單介紹了一下 Spring Batch,讓大家有個簡答的概念,今天我們來看 Spring batch 裡面具體的概念。
穿梭機:
基於Spring Boot 2.x 的 Spring Batch 入門到放棄之旅
SpringBatch從入門到放棄001- HelloWorld
本篇文章的目錄如下:
1. JobRepository配置一個 JobRepository2. JobLauncher配置一個 JobLauncher3. JobExplorer4 JobOperator5. JobRegistry6. Batch Namespace1. JobRepository
存儲 Job 的倉庫,可以配置成 內存存儲或者資料庫存儲。如果實用資料庫可以支持重啟。
JobRepostitory 的接口定義如下:
JobRepository接口定義
JobRepositoryFactoryBean的接口籤名如下,裡面我們可以看出需要指定數據源等信息。
JobRepositoryFactoryBean的接口籤名
配置一個 JobRepository
我們知道,在@EnableBatchProcess 註解之後,Spring Boot 會幫我自動配置一套 Spring Batch 的配置, 我們來通過 Spring Boot 的源碼來解析一下如何注入一個 JobRepository。
Spring Boot的所有自動配置都包含在spring.boot.autoconfigure.jar 這個 jar 中。根據 Spring 的加載規則,自動配置的類需要 spring.factories 中引入,所以我們打開這個文件,找到 batch 相關的配置
Spring Boot2 中自動配置類
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration 但是我們在這個類中只看到 JobRepository 的引用,並沒有他的 Bean註解,所以一定是在這個之前已經引入了這個類的配置:
@Configuration@ConditionalOnClass({ JobLauncher.class, DataSource.class, JdbcOperations.class })@AutoConfigureAfter(HibernateJpaAutoConfiguration.class)@ConditionalOnBean(JobLauncher.class)@EnableConfigurationProperties(BatchProperties.class)@Import(BatchConfigurerConfiguration.class)public class BatchAutoConfiguration {如果我們的猜想沒錯的話,從上邊我們不難看出JobRepository 的定義一定是在 BatchConfigurerConfiguration.class 中,我們打開這個類。
@ConditionalOnClass(PlatformTransactionManager.class)@ConditionalOnMissingBean(BatchConfigurer.class)@Configurationclass BatchConfigurerConfiguration { @Configuration @ConditionalOnMissingBean(name = "entityManagerFactory") static class JdbcBatchConfiguration { @Bean public BasicBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) { return new BasicBatchConfigurer(properties, dataSource, transactionManagerCustomizers.getIfAvailable()); } } @Configuration @ConditionalOnClass(EntityManagerFactory.class) @ConditionalOnBean(name = "entityManagerFactory") static class JpaBatchConfiguration { @Bean public JpaBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers, EntityManagerFactory entityManagerFactory) { return new JpaBatchConfigurer(properties, dataSource, transactionManagerCustomizers.getIfAvailable(), entityManagerFactory); } }}然並卵,我們還是沒有找到對應的 JobRepository的註解,等等,BasicBatchConfigurer.java這個好像是貓膩,我們打開這個這個類,果真裡面就有private JobRepository jobRepository; 我們開看一下他是怎麼初始化的,首先裡面有個@PostConstruct 註解的initialize()方法,
@PostConstruct public void initialize() { try { this.transactionManager = buildTransactionManager(); this.jobRepository = createJobRepository(); this.jobLauncher = createJobLauncher(); this.jobExplorer = createJobExplorer(); } catch (Exception ex) { throw new IllegalStateException("Unable to initialize Spring Batch", ex); } }在這個方法裡面調用了createJobRepository(),下邊就是默認創建JobRepository所需要傳入的屬性。如果我們自定義JobRepository,同樣的我們也需要傳入這些屬性。
protected JobRepository createJobRepository() throws Exception { JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); PropertyMapper map = PropertyMapper.get(); map.from(this.dataSource).to(factory::setDataSource); map.from(this::determineIsolationLevel).whenNonNull().to(factory::setIsolationLevelForCreate); map.from(this.properties::getTablePrefix).whenHasText().to(factory::setTablePrefix); map.from(this::getTransactionManager).to(factory::setTransactionManager); factory.afterPropertiesSet(); return factory.getObject(); }你也許會有疑問,BatchConfigurerConfiguration.java 中有這個註解 @ConditionalOnMissingBean(BatchConfigurer.class),而我們打開BatchConfigurer.java 這個接口的實現類,發現有個DefaultBatchConfigurer.java 被註解了進來,那為什麼BatchConfigurerConfiguration.java裡面的另外兩個註解還是生效了呢?這就是SpringBoot 設計的精妙之處了。
@Componentpublic class DefaultBatchConfigurer implements BatchConfigurer {當我們程序中注入了 Database 相關的參數,spring boot 會默認初始化一個entityManagerFactory 而一旦有兩個這個
被 static 修飾的JdbcBatchConfiguration 和 JpaBatchConfiguration就會生效,這個時候就會注入基於資料庫存儲的 JopRepository。
@ConditionalOnClass(EntityManagerFactory.class)@ConditionalOnBean(name = "entityManagerFactory")那如果不配置 Datasource 呢?如果我們程序中不注入一個 Datasource ,程序就會報錯。也就是說 Spring Boot 默認是必須使用資料庫版本的。如果想不使用,只能自己實現一個 BatchConfig.java 接口了。
2. JobLauncher
一個根據 Job 名稱和 JobParameters 觸發 batch 的接口,不管觸發成功與否都會返回一個 JobExecution 對象。如果當前的 JobName 和 JobParameters 已經對應一個 JobExecution ,則返回這個,如果麼有則新建一個。
定義如下:
public interface JobLauncher { public JobExecution run(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException;}配置一個 JobLauncher
正常情況下Spring boot 會幫我們創建一個默認的 JobLauncher,如果想客戶化這個配置,可以參考 JobRepository.
protected JobLauncher createJobLauncher() throws Exception { SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); jobLauncher.setJobRepository(getJobRepository()); jobLauncher.afterPropertiesSet(); return jobLauncher; }3. JobExplorer
提供了在運行期Mete-Data 數據的只讀操作
JobExplorer
接口定義如下:
接口定義
參照之前的方法,下邊我們在 Spring Boot 找到的默認實現的方法:
protected JobExplorer createJobExplorer() throws Exception { PropertyMapper map = PropertyMapper.get(); JobExplorerFactoryBean factory = new JobExplorerFactoryBean(); factory.setDataSource(this.dataSource); map.from(this.properties::getTablePrefix).whenHasText().to(factory::setTablePrefix); factory.afterPropertiesSet(); return factory.getObject(); }4 JobOperator
之前介紹JobRepository 提供了對 meta-data 的增刪改查。JobExplorer則提供了在運行期對這些數據的只讀操作。但是一些常見的監視操作如,停止,重啟,匯總等對於業務操作人員是非常有用的,JobOperator 則提供了這些操作。
JobOperator 接口的定義:
JobOperator
配置一個簡單的例子:
@Bean public SimpleJobOperator jobOperator(JobExplorer jobExplorer, JobRepository jobRepository, JobRegistry jobRegistry) { SimpleJobOperator jobOperator = new SimpleJobOperator(); jobOperator.setJobExplorer(jobExplorer); jobOperator.setJobRepository(jobRepository); jobOperator.setJobRegistry(jobRegistry); jobOperator.setJobLauncher(jobLauncher); return jobOperator; }5. JobRegistry
JobRegistry (父接口為 JobLocator )並非強制使用,它能夠協助用戶在上下文中追蹤job是否可用,也能夠在應用上下文收集在其他地方(子上下文)創建的job信息。自定義的JobRegistry實現常被用於操作job的名稱或是其他屬性。框架提供了一個基於map的默認實現,能夠從job的名稱映射到job的實例
MapJobRegistry
6. Batch Namespace
Spring Boot 之後大家已經習慣了基於 JavaConfig 的配置,但是 Batch 依然支持基於 XML 的配置,在官方文檔中,基本上兩種方式的配置都會提供。上邊提到的領域模型概念在基於 XML 的配置中,雖然使用標準的 Beans 空間也可以配置,但是 Batch 還是提供了自己的命名空間,讓配置變得更方便,下邊就是一個配置的例子:
<beans:beans xmlns="http://www.springframework.org/schema/batch" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/batch https://www.springframework.org/schema/batch/spring-batch.xsd"> <job id="ioSampleJob"> <step id="step1"> <tasklet> <chunk reader="itemReader" writer="itemWriter" commit-interval="2"/> </tasklet> </step> </job> </beans:beans>上邊提到的 schema 在 spring-batch-core中有指定,我們看到現在默認的是使用 spring-batch-3.0.xsd
spring-batch.xsd
3.0的 XSD 的具體結構和約束可以在下邊路徑中找到。
spring-batch-3.0.xsd
至此 Spring Batch 的核心概念就介紹完了,下一篇我們將介紹具體的實例概念如 Job,Step 等。