1. 程式人生 > >整合spring boot + quartz + spring batch + mybatis

整合spring boot + quartz + spring batch + mybatis

quartz負責定時,spring batch負責批量,mybatis負責持久化資料庫,具體每個框架的介紹請參考其它文章,本節主要做spring boot + quartz + spring batch + mybatis的整合。

案例:指定距當前時間5s後,每隔3s時間執行一次批處理任務,批處理任務是讀取資料庫表記錄並打印出來。
資料庫採用DB2資料庫,庫表為users,記錄為:
這裡寫圖片描述

一、建立一個spring boot工程,並在pom.xml中引入依賴jar包

<?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> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.9</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>

二、配置定時

spring-context-support的jar包作了quartz和spring batch的整合。QuartzJobBean類起連線quartz和spring batch的作用。quartz定時執行QuartzJobBean的繼承類,在繼承類中去執行啟動批量任務,達到定時啟動批量的作用。
1、建立QuartzJobBean的繼承類

package com.lzj.quartz;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.h2.util.New;
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.JobParametersBuilder;
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 {
/*-------------方式一:獲取jobName、jobLauncher和jobLocator*/
//  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 {
/*-------------方式二:獲取jobName、jobLauncher和jobLocator-------------------*/
        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);
/*-----------------------------方式二獲取結束---------------------------------*/
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = sf.format(new Date());
        System.out.println("Current Time : " + date);

        try {
            Job job = jobLocator.getJob(jobName);
            /*啟動spring batch的批處理作業*/
            JobExecution jobExecution = jobLauncher.run(job, new JobParametersBuilder().addDate("date", new Date()).toJobParameters());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

2、配置定時任務

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="quartzJob" class="com.lzj.quartz.QuartzJobLauncher"></bean>
    <!-- 註冊job -->
    <bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry"></bean>

    <bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
        <property name="jobRegistry" ref="jobRegistry"></property>
    </bean>

    <!-- jobLauncher在batch-config.xml檔案中定義了 -->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.lzj.quartz.QuartzJobLauncher"></property>
        <property name="jobDataMap">
            <map>
                <entry key="jobName" value="myJob"></entry>
                <entry key="jobLauncher" value-ref="jobLauncher"></entry>
                <entry key="jobLocator" value-ref="jobRegistry"></entry>
            </map>
        </property>
    </bean>

    <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="jobDetail"></property>
        <property name="cronExpression" value="0/3 * * * * ?"></property>
        <property name="startDelay" value="3000"></property>
    </bean>

    <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers" ref="cronTrigger"></property>
    </bean>

</beans>

三、配置spring batch的job作業

1、首先建立batch的作業類,實現Tasklet介面即可
程式中用到的UserDao 與資料庫打交道的介面在後面通過mybatis進行定義。

package com.lzj.springbatch.tasklet;
import java.util.List;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import com.lzj.mybatis.dao.UserDao;
import com.lzj.springbatch.model.User;

public class MyTasklet implements Tasklet {
    /*在配置檔案batch-confi.xml中定義MyTasklet的bean時,傳入UserDao 的屬性*/
    private UserDao userDao;

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        User user = new User();
        user.setId(1);
        List<User> users = userDao.select(user);
        for(User user1 : users){
            System.out.println(user1);
        }
        return RepeatStatus.FINISHED;
    }
}

2、配置job作業

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:batch="http://www.springframework.org/schema/batch"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">

<!--    <context:property-placeholder location="classpath:db.properties"/> --> 

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>

    <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository"></property>
    </bean>

    <batch:job id="myJob" restartable="true">
        <batch:step id="myStep" allow-start-if-complete="true">
            <batch:tasklet ref="myTasklet">
            </batch:tasklet>
        </batch:step>
    </batch:job>

    <bean id="myTasklet" class="com.lzj.springbatch.tasklet.MyTasklet">
<!--        <property name="dataSource" ref="dataSource"></property>  -->
        <property name="userDao" ref="userDao"></property>
    </bean>

</beans>

四、配置mybatis的持久化層

1、在spring boot中整合mybatis的配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">

    <bean id="propertyConfigure"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:db.properties</value>
            </list>
        </property>
    </bean>

    <!--spring batch和mybatis共用一個數據源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.jdbcUrl}" />
        <property name="username" value="${jdbc.user}" />
        <property name="password" value="${jdbc.password}" />
        <property name="driverClassName" value="${jdbc.driverClass}" />
        <property name="initialSize" value="3" />
        <property name="minIdle" value="3" />
        <property name="maxActive" value="3" />
        <!-- 配置獲取連線等待超時的時間 -->
        <property name="maxWait" value="60000" />
        <!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閒連線,單位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一個連線在池中最小生存的時間,單位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="300000" />
        <property name="testWhileIdle" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
    </bean>


    <!-- 申明式事務 -->
    <tx:annotation-driven transaction-manager="transactionManager" />

    <!--mybatis-config.xml為mybatis的一些屬性配置,如無必須要求,可不配置-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis-config.xml" /> 
        <!-- <property name="typeAliasesPackage" value="domain.bean" /> -->
        <property name="mapperLocations">
            <array>
                <value>classpath:mapper/*.xml</value>
            </array>
        </property>
    </bean>

    <!-- 配置載入Dao -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.lzj.mybatis.dao"></property>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
    </bean>

</beans>

mybatis-config.xml中只配置了開啟mybatis的二級快取功能

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
    <settings>
        <setting name="cacheEnabled" value="true" />
    </settings>
</configuration>

資料庫的properties檔案db.properties為:

jdbc.user=my_name
jdbc.password=my_password
jdbc.driverClass=com.ibm.db2.jcc.DB2Driver
jdbc.jdbcUrl=jdbc:db2:xx.xxx.xx.xxx:50000/database_name

2、建立mybatis的介面,程式通過介面來操作mybatis與資料庫互動

package com.lzj.mybatis.dao;
import java.util.List;
import com.lzj.springbatch.model.User;
public interface UserDao {
    public List<User> select(User user);
}

3、編寫mybatis的mapper檔案,介面操作mapper檔案,

mapper檔案與資料庫互動
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lzj.mybatis.dao.UserDao">
    <resultMap type="com.lzj.springbatch.model.User" id="ResultMap">
        <result column="ID" property="id"/>
        <result column="NAME" property="name"/>
        <result column="AGE" property="age"/>
    </resultMap>

    <select id="select" resultMap="ResultMap">
        select * from SQLJ.users
        <where>
            <if test="id != null">ID > #{id}</if>
        </where>
    </select>
</mapper>

五、run

測試方法如下:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {

        Set<Object> set = new HashSet<>();
        set.add("classpath:batch-config.xml");
        set.add("classpath:quartz-config.xml");
        set.add("applicationContext.xml");
        SpringApplication app = new SpringApplication(DemoApplication.class);
        app.setSources(set);
        ApplicationContext context = app.run(args);
    }
}

啟動測試方法,輸出日誌如下:

……
jobName : myJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@4ba309ec
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@4564eee8
Current Time : 2018-04-13 19:48:00
2018-04-13 19:48:00.032  INFO 4788 --- [eduler_Worker-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] launched with the following parameters: [{date=1523620080009}]
2018-04-13 19:48:00.090  INFO 4788 --- [eduler_Worker-2] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=2, name=huwei, age=28]
User [id=3, name=lijie, age=26]
2018-04-13 19:48:00.140  INFO 4788 --- [eduler_Worker-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] completed with the following parameters: [{date=1523620080009}] and the following status: [COMPLETED]
jobName : myJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@4ba309ec
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@4564eee8
Current Time : 2018-04-13 19:48:03
2018-04-13 19:48:03.017  INFO 4788 --- [eduler_Worker-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] launched with the following parameters: [{date=1523620083000}]
2018-04-13 19:48:03.057  INFO 4788 --- [eduler_Worker-3] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=2, name=huwei, age=28]
User [id=3, name=lijie, age=26]
2018-04-13 19:48:03.089  INFO 4788 --- [eduler_Worker-3] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] completed with the following parameters: [{date=1523620083000}] and the following status: [COMPLETED]
jobName : myJob
jobLauncher : org.springframework.batch.core.launch.support.SimpleJobLauncher@4ba309ec
jobLocator : org.springframework.batch.core.configuration.support.MapJobRegistry@4564eee8
Current Time : 2018-04-13 19:48:06
2018-04-13 19:48:06.019  INFO 4788 --- [eduler_Worker-4] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] launched with the following parameters: [{date=1523620086001}]
2018-04-13 19:48:06.058  INFO 4788 --- [eduler_Worker-4] o.s.batch.core.job.SimpleStepHandler     : Executing step: [myStep]
User [id=2, name=huwei, age=28]
User [id=3, name=lijie, age=26]
2018-04-13 19:48:06.094  INFO 4788 --- [eduler_Worker-4] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=myJob]] completed with the following parameters: [{date=1523620086001}] and the following status: [COMPLETED]
……

通過日誌可以看出,每3s執行一次job任務

工程目錄為:
這裡寫圖片描述