基于编码配置方式整合Spring boot + Spring batch + Quartz

前面一节中已经介绍了基于xml配置方式整合Spring boot + Spring batch + Quartz ,本节介绍基于编码配置方式整合Spring boot + Spring batch + Quartz。具体spring batch和quartz的使用请看其它参考,下面进行整合。
案例:定时,在距当前5s后,每隔3s执行一次job任务,job任务是读取User.txt文件中内容,并把每条记录中年纪为偶数的记录打印出来。
User.txt中的内容为:

ID,NAME,AGE
1,lzj,28
2,tom,20
3,terry,30
4,lerry,18
5,bob,25
6,linda,27
7,marry,39
8,long,22
9,kin,33
10,jiken,40

一、创建一个spring boot工程,并引入下面所需要的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.lzj</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> 
            <scope>runtime</scope> </dependency> -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

创建User.txt中每条记录对应的POJO

package com.lzj.springbatch.model;
public class User {
    private String id;
    private String name;
    private String age;
    /*省略get/set/toString方法*/
}

二、创建spring batch的job,并配置job

1、创建spring batch的读文件类。spring batch中提供了用于读文件的类

FlatFileItemReader,在此只需继承该类,并设置读文件的属性
package com.lzj.springbatch.reader;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.validation.BindException;
import com.lzj.springbatch.model.User;

public class MyReader extends FlatFileItemReader<User> {
    public MyReader(){
        createReader();
    }

    private void createReader(){
        this.setResource(new ClassPathResource("data/User.txt"));
        this.setLinesToSkip(1);
        this.setLineMapper(userLineMapper());
    }

    private LineMapper<User> userLineMapper(){
        DefaultLineMapper<User> lineMapper = new DefaultLineMapper<>();
        lineMapper.setLineTokenizer(userLineTokenizer());
        lineMapper.setFieldSetMapper(new UserFieldStepMapper());
        lineMapper.afterPropertiesSet(); 
        return lineMapper;
    }

    private LineTokenizer userLineTokenizer(){
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
        tokenizer.setNames(new String[]{"ID", "NAME", "AGE"});
        return tokenizer;
    }

    private static class UserFieldStepMapper implements FieldSetMapper<User>{
        @Override
        public User mapFieldSet(FieldSet fieldSet) throws BindException {
            return new User(fieldSet.readString("ID"), 
                    fieldSet.readString("NAME"), 
                    fieldSet.readString("AGE"));
        }

    }
}

2、创建spring batch的处理类,实现ItemProcessor接口,覆写process方法,reader方法中读取文件一条记录放入User对象中,在process方法中处理User对象,只选择年龄为偶数的User对象传给spring batch的writer类

package com.lzj.springbatch.processor;
import org.springframework.batch.item.ItemProcessor;
import com.lzj.springbatch.model.User;

public class MyProcessor implements ItemProcessor<User, User> {

    @Override
    public User process(User item) throws Exception {
        if (Integer.parseInt(item.getAge()) % 2 == 0) {
            return item;
        }
        return null;
    }
}

3、创建spring batch的writer类,只需继承ItemWriter接口,覆写write方法即可。打印出处理类处理后的User对象

package com.lzj.springbatch.writer;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
import com.lzj.springbatch.model.User;

public class MyWriter implements ItemWriter<User> {
    @Override
    public void write(List<? extends User> items) throws Exception {
        for(User user : items){
            System.out.println(user);
        }
    }
}

4、创建job,并配置job

package com.lzj.springbatch.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.lzj.quartz.QuartzConfiguration;
import com.lzj.springbatch.model.User;
import com.lzj.springbatch.processor.MyProcessor;
import com.lzj.springbatch.reader.MyReader;
import com.lzj.springbatch.writer.MyWriter;

@Configuration
@EnableBatchProcessing
//@Import({QuartzConfiguration.class})
public class BatchConfiguration {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;
    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    /*创建job*/
    @Bean
    public Job jobMethod(){
        return jobBuilderFactory.get("lzjJob")
                .start(stepMethod())
                .build();
    }

    /*创建step*/
    @Bean
    public Step stepMethod(){
        return stepBuilderFactory.get("myStep")
                .<User, User>chunk(3)
                .reader(new MyReader())
                .processor(new MyProcessor())
                .writer(new MyWriter())
                .allowStartIfComplete(true)
                .build();
    }

}

三、用quartz进行定时配置job任务

spring家族中的spring-context-support 的jar包整合了quartz定时,用来整合spring batch和quartz的开发。
1、创建执行spring batch的job的接口。spring-context-support包中的QuartzJobBean是quartz执行spring batch的job的接口,只需实现该接口,并覆写executeInternal方法,在executeInternal方法中启动job。并在后面介绍定时执行该接口实现类中的executeInternal方法,达到定时执行spring batch 的job的功能。

package com.lzj.quartz;

import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.JobLocator;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class QuartzJobLauncher extends QuartzJobBean {
/*方式一*/
//  private String jobName;
//  private JobLauncher jobLauncher;
//  private JobLocator jobLocator;
//
//  public String getJobName() {
//      return jobName;
//  }
//
//  public void setJobName(String jobName) {
//      this.jobName = jobName;
//  }
//
//  public JobLauncher getJobLauncher() {
//      return jobLauncher;
//  }
//
//  public void setJobLauncher(JobLauncher jobLauncher) {
//      this.jobLauncher = jobLauncher;
//  }
//
//  public JobLocator getJobLocator() {
//      return jobLocator;
//  }
//
//  public void setJobLocator(JobLocator jobLocator) {
//      this.jobLocator = jobLocator;
//  }
//
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        /*方式二*/
        JobDetail jobDetail = context.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        String jobName = jobDataMap.getString("jobName");
        JobLauncher jobLauncher = (JobLauncher) jobDataMap.get("jobLauncher");
        JobLocator jobLocator = (JobLocator) jobDataMap.get("jobLocator");
        System.out.println("jobName : " + jobName);
        System.out.println("jobLauncher : " + jobLauncher);
        System.out.println("jobLocator : " + jobLocator);
        JobKey key = context.getJobDetail().getKey();
        System.out.println(key.getName() + " : " + key.getGroup());

        try {
            Job job = jobLocator.getJob(jobName);
            /*启动spring batch的job*/
            JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

2、创建定时器,定时触发spring batch 的job任务

package com.lzj.quartz;

import java.util.HashMap;
import java.util.Map;

import org.springframework.batch.core.configuration.JobLocator;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class QuartzConfiguration {

    //自动注入进来的是SimpleJobLauncher
    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    private JobLocator jobLocator;

    /*用来注册job*/
    /*JobRegistry会自动注入进来*/
    @Bean
    public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry){
        JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
        jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
        return jobRegistryBeanPostProcessor;
    }

    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean jobFactory = new JobDetailFactoryBean();
        jobFactory.setJobClass(QuartzJobLauncher.class);
        jobFactory.setGroup("my_group");
        jobFactory.setName("my_job");
        Map<String, Object> map = new HashMap<>();
        map.put("jobName", "lzjJob");
        map.put("jobLauncher", jobLauncher);
        map.put("jobLocator", jobLocator);
        jobFactory.setJobDataAsMap(map);
        return jobFactory;
    }

    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(){
        CronTriggerFactoryBean cTrigger = new CronTriggerFactoryBean();
        System.out.println("------- : " + jobDetailFactoryBean().getObject());
        cTrigger.setJobDetail(jobDetailFactoryBean().getObject());
        cTrigger.setStartDelay(5000);
        cTrigger.setName("my_trigger");
        cTrigger.setGroup("trigger_group");
        cTrigger.setCronExpression("0/3 * * * * ? "); //每间隔5s触发一次Job任务
        return cTrigger;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(){
        SchedulerFactoryBean schedulerFactor = new SchedulerFactoryBean();
        schedulerFactor.setTriggers(cronTriggerFactoryBean().getObject());
        return schedulerFactor;
    }

}

四、Run

启动spring boot工程,启动类为

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args){
        SpringApplication.run(DemoApplication.class, args);
    }
}

在application.properties中添加

spring.batch.job.enabled=false

表示在启动工程的时候不执行job,在定时触发时再执行job任务。

执行启动类,输出日志如下:

……
jobName : lzjJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@26adcd69
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@62d05170
my_job : my_group
Current time : 2018-04-12 22:48:39
2018-04-12 22:48:39.066  INFO 1820 --- [ryBean_Worker-1] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=lzjJob]] launched with the following parameters: [{}]
2018-04-12 22:48:39.084  INFO 1820 --- [ryBean_Worker-1] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=1, name=lzj, age=28]
User [id=2, name=tom, age=20]
User [id=3, name=terry, age=30]
User [id=4, name=lerry, age=18]
User [id=8, name=long, age=22]
User [id=10, name=jiken, age=40]
2018-04-12 22:48:39.119  INFO 1820 --- [ryBean_Worker-1] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=lzjJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
jobName : lzjJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@26adcd69
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@62d05170
my_job : my_group
Current time : 2018-04-12 22:48:42
2018-04-12 22:48:42.021  INFO 1820 --- [ryBean_Worker-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=lzjJob]] launched with the following parameters: [{}]
2018-04-12 22:48:42.029  INFO 1820 --- [ryBean_Worker-2] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=1, name=lzj, age=28]
User [id=2, name=tom, age=20]
User [id=3, name=terry, age=30]
User [id=4, name=lerry, age=18]
User [id=8, name=long, age=22]
User [id=10, name=jiken, age=40]
2018-04-12 22:48:42.046  INFO 1820 --- [ryBean_Worker-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=lzjJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
jobName : lzjJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@26adcd69
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@62d05170
my_job : my_group
Current time : 2018-04-12 22:48:45
2018-04-12 22:48:45.009  INFO 1820 --- [ryBean_Worker-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=lzjJob]] launched with the following parameters: [{}]
2018-04-12 22:48:45.016  INFO 1820 --- [ryBean_Worker-3] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=1, name=lzj, age=28]
User [id=2, name=tom, age=20]
User [id=3, name=terry, age=30]
User [id=4, name=lerry, age=18]
User [id=8, name=long, age=22]
User [id=10, name=jiken, age=40]
2018-04-12 22:48:45.039  INFO 1820 --- [ryBean_Worker-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=lzjJob]] completed with the following parameters: [{}] and the following status: [COMPLETED]
……

从日志中可以看出,每3s解析一次User.txt文件,并把满足条件的记录打印出来。

工程目录为:
这里写图片描述

源码参考位置:https://github.com/shuniversity/springboot-quartz-springbatch

猜你喜欢

转载自blog.csdn.net/u010502101/article/details/79921675