SpringBatch从入门到放弃001- Hello World

经常有人问我,有没有一个 Spring Batch 的例子可以参考一下,之前的我的回答一般是百度自己找,太多了。但是后来我发现因为 Spring Batch的版本太稳定,网上的例子大部分都是基于3.X版本的,还有就是对应的 Spring Boot 的版本也是比较老的。针对这种情况,我决定根据最新 release(4.1.2)的官方文档,来写一套最新的例子,供朋友参考。

Spring Boot 集成了 Spring Batch,如果想在程序钟启用 Spring Batch 的话,只需要添加@EnableBatchProcessing 注解即可,Spring Boot 会根据预置的 @BatchAutoConfiguration引入必要的配置。

Spring Boot 文档中对 Spring Batch的描述。

下边我们就来基于 Spring Boot 搭建一个 Hello World 的 Spring Batch。我先假想一个简单的需求:读取某一个目录的文件,加工一下,再写入另外一个文件。

Step 1: 新建一个 Spring Boot 的工程

我们通过 IDEA新建一个 Spring Boot的工程,在新建的时候引入两个必要的依赖:

  1. Spring Batch: 运行 Spring Batch
  2. MySQL Driver: 需要通过Spring Batch 需要通过数据库存储Job 的运行数据

打开 POM 我们会发现其实引入batch 的 starter。再 starter 里面封装了 batch-core。

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

既然引入了 MySQL 的依赖,就配置一个数据源吧,打开 application.properties 文件添加数据源配置(Spring Boot 默认的数据库连接池,所以只要指定数据库连接信息就好了),

spring.datasource.username=XXX
spring.datasource.password=XXX
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url= jdbc:mysql://localhost:3306/batch_config?zeroDateTimeBehavior=convertToNull

我们需要再程序运行的时候初始化数据库,再application.properties 添加下边两个参数。

#程序启动的时候初始化一个空数据结构
spring.batch.initialize-schema=embedded

#程序启动的时候不运行任何 Job
spring.batch.job.enabled=false

Step2: 定义Reader/Processor/Writer

根据我们假想出来的需求,我们需要定一个 Reader 来读取我们的文件,Spring Batch 内置了很多很好用的 Reader,后边章节我也会详细的介绍,这里我们选用FlatFileItemReader来读取文件,Spring Batch 提供了FlatFileItemReaderBuilder来帮助我们构建FlatFileItemReader,我们只需要指定几个简单的属性,就可以完成一个读取文件的 Reader。代码如下:

    @StepScope
    @Bean
    public ItemReader<String> itemReader(){
        //FlatFileItemReader
        return new FlatFileItemReaderBuilder<String>()
                .name("simpleFileReader")
                .resource(new ClassPathResource("batch-data/2019072401.txt"))
                .lineMapper(new PassThroughLineMapper())
                .build();
    }

文件读完之后,我们对读出来的每一行统一添加一个字符串来模拟Batch 的处理过程。我们通过实现一个匿名来完成添加字符串的操作:

    @StepScope
    @Bean
    public ItemProcessor<String,String> itemProcessor(){
        return new ItemProcessor<String, String>() {
            @Override
            public String process(String item) throws Exception {
                return "[linghuxiong]"+item;
            }
        };
    }

处理完读出来的内容之后我们就需要将读出来的字符串写到数据库或者文件系统里面了,我们假想的需求是写文件。同样的 Spring Batch 官方提供了很多内置的 Writer。因为是写文件,我们选用FlatFileItemWriter作为我们的 Writer,同样的我们使用FlatFileItemWriterBuilder来构建我们的FlatFileItemWriter[Spring Batch 4 对FlatFileItemWriterBuilder 进行了增强,详见官方文档]。

    @StepScope
    @Bean
    public ItemWriter<String> itemWriter(){
        return new FlatFileItemWriterBuilder<String>()
                .name("simpleFileWriter")
                .lineAggregator(new PassThroughLineAggregator<String>())
                .resource(new FileSystemResource("/Users/eric/Documents/dev/linghuxiong/spring-boot-demo/batch/target/2019072402.txt"))
                .build();
    }

至此我们的Reader/Processor/Writer 就已经构建完毕了,这就相当于零件已经备好,下边我们通过构建 Step/Job 来组装我们的 Batch。

Step 3: 构建 Step /Job

再给项目添加@EnableBatchProcessing之后,就会默认将 Batch 需要对象注入到 Context 中,其中就有构建 Step 的StepBuilderFactory和构建 Job 的JobBuilderFactory。下边我们就用这两个 Factory 来构建我们的 Step 和 Job。

首先注入这两个 Factory :

    @Autowired
    JobBuilderFactory jobBuilderFactory;

    @Autowired
    StepBuilderFactory stepBuilderFactory;

将 Step2 中的零件组装成一个 Step:

    @Bean
    public Step step1(){
        return stepBuilderFactory.get("step1")
                .<String,String>chunk(2)
                .reader(itemReader())
                .processor(itemProcessor())
                .writer(itemWriter())
                .build();
    }

将 Step 放入 Job 中:

    @Bean
    public Job job1(){
        return jobBuilderFactory.get("job1").start(step1()).build();
    }

经过以上两步,我们的 Job 就定义完成了。下边我们就来测试一下我们写的 Job 是否正确:

Step 4: 测试一个 Job

Spring Batch 4.X 提供了一个 @SpringBatchTest 会帮助我们构建一个 Batch 的执行环境,比如:JobLauncherTestUtils/JobRepositoryTestUtils 两个类。

@RunWith(SpringRunner.class)
@SpringBatchTest
@SpringBootTest
public class JobTest {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Autowired
    private JobRepositoryTestUtils jobRepositoryTestUtils;
    
    … … … …
}

在测试我们的Job 之前,我们需要先清空我们的测试库,这样就不会因为上一次的失败,而引入的脏数据来影响我们这一次的测试。

    @Before
    public void clearMetadata() {
        jobRepositoryTestUtils.removeJobExecutions();
    }

编写一个简单的测试 CASE,运行我们的 JOB,并判单是否正常结束:

    @Test
    public void testJob() throws Exception {

        // given
        JobParameters jobParameters =
                jobLauncherTestUtils.getUniqueJobParameters();

        // when
        JobExecution jobExecution =
                jobLauncherTestUtils.launchJob(jobParameters);

        // then
        Assert.assertEquals(ExitStatus.COMPLETED,
                jobExecution.getExitStatus());
    }

好了,截止到先,我们的 Hello World 的所有代码都已经编写结束了。整体的项目结构如下:

运行我们Junit Case , 运行成功之后就会在 Writer 指定的文件目录下边生成我们处理之后的文件。

同时在我们配置的数据库中,会初始化Batch 框架自己所需要的表:

鹏哥已经上传了源代码:源代码地址

猜你喜欢

转载自www.cnblogs.com/ckp-henu/p/springbatch-cong-ru-men-dao-fang-qi001-hello-world.html