bat对java工程师 java batch开发_Source

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 的接口定义如下:

bat对java工程师 java batch开发_spring_02

JobRepository接口定义

JobRepositoryFactoryBean的接口签名如下,里面我们可以看出需要指定数据源等信息。

bat对java工程师 java batch开发_bat对java工程师_03

JobRepositoryFactoryBean的接口签名

配置一个 JobRepository

我们知道,在@EnableBatchProcess 注解之后,Spring Boot 会帮我自动配置一套 Spring Batch 的配置, 我们来通过 Spring Boot 的源码来解析一下如何注入一个 JobRepository。

Spring Boot的所有自动配置都包含在spring.boot.autoconfigure.jar 这个 jar 中。根据 Spring 的加载规则,自动配置的类需要 spring.factories 中引入,所以我们打开这个文件,找到 batch 相关的配置

bat对java工程师 java batch开发_java_04

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) { 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, 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 数据的只读操作

bat对java工程师 java batch开发_java中batch基础_05

JobExplorer

接口定义如下:

bat对java工程师 java batch开发_java中batch基础_06

接口定义

参照之前的方法,下边我们在 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 接口的定义:

bat对java工程师 java batch开发_bat对java工程师_07

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的实例

bat对java工程师 java batch开发_Source_08

MapJobRegistry

6. Batch Namespace

Spring Boot 之后大家已经习惯了基于 JavaConfig 的配置,但是 Batch 依然支持基于 XML 的配置,在官方文档中,基本上两种方式的配置都会提供。上边提到的领域模型概念在基于 XML 的配置中,虽然使用标准的 Beans 空间也可以配置,但是 Batch 还是提供了自己的命名空间,让配置变得更方便,下边就是一个配置的例子:

上边提到的 schema 在 spring-batch-core中有指定,我们看到现在默认的是使用 spring-batch-3.0.xsd

bat对java工程师 java batch开发_java_09

spring-batch.xsd

3.0的 XSD 的具体结构和约束可以在下边路径中找到。

bat对java工程师 java batch开发_spring_10

spring-batch-3.0.xsd

至此 Spring Batch 的核心概念就介绍完了,下一篇我们将介绍具体的实例概念如 Job,Step 等。