SpringBatch从入门到放弃002- 核心概念1

1. JobRepository

存储 Job 的仓库,可以配置成 内存存储 或者数据库存储 。如果实用数据库可以支持重启。
JobRepostitory 的接口定义如下:

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

配置一个 JobRepository

我们知道,在@EnableBatchProcess 注解之后,Spring Boot 会帮我自动配置一套 Spring Batch 的配置, 我们来通过 Spring Boot 的源码来解析一下如何注入一个 JobRepository。
Spring Boot的所有自动配置都包含在spring.boot.autoconfigure.jar 这个 jar 中。根据 Spring 的加载规则,自动配置的类需要 spring.factories 中引入,所以我们打开这个文件,找到 batch 相关的配置

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)
@Configuration
class 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 设计的精妙之处了。

@Component
public 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 数据的只读操作

接口定义如下:

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

配置一个简单的例子:

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

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

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

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

猜你喜欢

转载自www.cnblogs.com/ckp-henu/p/springbatch-cong-ru-men-dao-fang-qi002-he-xin-gai.html