Quartz/Spring整合quartz

来自 https://segmentfault.com/a/1190000009972187

第一章:课程介绍

1-1 初识Quartz

Quartz概要

OpenSymphony提供的强大的开源任务调度框架
官网:http://www.quartz-scheduler.org
纯Java实现,精细控制排程

Quartz特点

强大的调度功能
灵活的应用方式
分布式和集群能力

Quartz的设计模式

Builder模式
Factory模式
组件模式
链式写法

Quartz三个核心概念

调度器:将任务和触发器一一对应
任务:需要做什么,值Service
触发器:定义时间

Quartz体系结构

JobDetail
trigger
    SimpleTrigger
    CronTrigger
scheduler
    start
    stop
    pause
    resume

示意图

clipboard.png

Quartz重要组成

Job
JobDetail
JobBuilder
JobStore
Trigger
TriggerBuilder
ThreadPool
Scheduler
Calendar:一个Trigger可以和多个Calendar关联,以排除或包含某些时间点
监听器
    JobListener
    TriggerListener
    SchedulerListener

第二章:Quartz详解

2-1 第一个Quartz程序

准备工作

建立Maven项目工程
引入Quartz包

编写第一个Quartz任务

让任务每隔两秒打印一次hellworld

代码演示

1.编写任务类

package com.myimooc.helloquartz.one;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * 编写 自定义任务
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloJob implements Job{
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is : " + sf.format(date));
        
        // 编写具体的业务逻辑
        System.out.println("Hello World!");
    }
    
}

2.编写任务调度类

package com.myimooc.helloquartz.one;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 编写 任务调度类
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloScheduler {
    
    public static void main(String[] args) throws SchedulerException {
        
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 实例绑定
        JobDetail jobDeatil = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myjob", "jobgroup1")// 定义标识符
                .build();
        
        System.out.println("jobDetail's name : " + jobDeatil.getKey().getName());
        System.out.println("jobDetail's group : " + jobDeatil.getKey().getGroup());
        System.out.println("jobDetail's jobClass : " + jobDeatil.getJobClass().getName());
        
        // 创建一个 Trigger 实例,定义该 job 立即执行,并且每隔两秒重复执行一次,直到永远
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger","trigroup1")// 定义标识符
                .startNow()// 定义立即执行
                .withSchedule(SimpleScheduleBuilder
                        .simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())// 定义执行频度
                .build();
        
        // 创建 Scheduler 实例
        SchedulerFactory sfact = new StdSchedulerFactory();
        Scheduler scheduler = sfact.getScheduler();
        
        // 绑定 JobDetail 和 trigger
        scheduler.scheduleJob(jobDeatil, trigger);
        
        // 执行任务
        scheduler.start();
        
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is : " + sf.format(date));
    }
    
}

2-2 浅谈Job&JobDetail

Job定义

实现业务逻辑的任务接口

浅谈Job

Job接口非常容易实现,只有一个execute方法,类似TimerTask的run方法,在里面编写业务逻辑
Job接口源码
public interface Job {
    void execute(JobExecutionContext context) throws JobExecutionException;
}

Job实例在Quartz中的生命周期

每次调度器执行job时,它在调用execute方法前会创建一个新的job实例
当调用完成后,关联的job对象实例会被释放,释放的实例会被垃圾回收机制回收

浅谈JobDetail

JobDetail为Job实例提供了许多设置属性,以及JobDetailMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。

JobDetail属性

name:任务名称
group:任务所属组
jobClass:任务实现类
jobDataMap:传参的作用

2-3 浅谈JobExecutionContext&JobDataMap(上)

JobExecutionContext是什么

Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;
Job能通过JobExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据。

JobDataMap是什么

在进行任务调度时JobDataMap存储在JobExecutionContext中,非常方便获取
JobDataMap可以用来装载任务可序列化的数据对象,当job实例对象被执行时这些参数对象会传递给它
JobDataMap实现了JDK的Map接口,并且添加了一些非常方便的方法用来存取基本数据类型

2-4 浅谈JobExecutionContext&JobDataMap(下)

获取JobDataMap的两种方式

从Map中直接获取
Job实现类中添加setter方法对应JobDataMap的键值
(Quartz框架默认的JobFactory实现类在初始化job实例对象时会自动地调用这些setter方式)

代码演示

1.HelloScheduler类改造

package com.myimooc.helloquartz.two;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 编写 任务调度类
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloScheduler {
    
    public static void main(String[] args) throws SchedulerException {
        
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 实例绑定
        JobDetail jobDeatil = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myjob", "jobgroup1")// 定义标识符
                .usingJobData("message", "hello myjob1")// 传入自定义参数
                .usingJobData("floatJobValue", 3.14F)// 传入自定义参数
                .build();
        
        System.out.println("jobDetail's name : " + jobDeatil.getKey().getName());
        System.out.println("jobDetail's group : " + jobDeatil.getKey().getGroup());
        System.out.println("jobDetail's jobClass : " + jobDeatil.getJobClass().getName());
        
        // 创建一个 Trigger 实例,定义该 job 立即执行,并且每隔两秒重复执行一次,直到永远
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger","trigroup1")// 定义标识符
                .usingJobData("message", "hello mytrigger1")// 传入自定义参数
                .usingJobData("doubleTriggerValue", 2.0D)// 传入自定义参数
                .startNow()// 定义立即执行
                .withSchedule(SimpleScheduleBuilder
                        .simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())// 定义执行频度
                .build();
        
        // 创建 Scheduler 实例
        SchedulerFactory sfact = new StdSchedulerFactory();
        Scheduler scheduler = sfact.getScheduler();
        
        // 绑定 JobDetail 和 trigger
        scheduler.scheduleJob(jobDeatil, trigger);
        
        // 执行任务
        scheduler.start();
        
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is : " + sf.format(date));
    }
    
}

2.HelloJob类改造

package com.myimooc.helloquartz.two;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.TriggerKey;

/**
 * 编写 自定义任务
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloJob implements Job{
    
    // 方式二:getter和setter获取
    // 成员变量 与 传入参数的key一致
    private String message;
    private Float floatJobValue;
    private Double doubleTriggerValue;
    
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public Float getFloatJobValue() {
        return floatJobValue;
    }
    public void setFloatJobValue(Float floatJobValue) {
        this.floatJobValue = floatJobValue;
    }
    public Double getDoubleTriggerValue() {
        return doubleTriggerValue;
    }
    public void setDoubleTriggerValue(Double doubleTriggerValue) {
        this.doubleTriggerValue = doubleTriggerValue;
    }
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is : " + sf.format(date));
        
        // 编写具体的业务逻辑
        //System.out.println("Hello World!");
        
        JobKey key = context.getJobDetail().getKey();
        System.out.println("My name and group are : " + key.getName() + " : " + key.getGroup());
        
        TriggerKey trkey = context.getTrigger().getKey();
        System.out.println("My Trigger name and group are : " + trkey.getName() + " : " + trkey.getGroup());
        
        // 方式一:Map中直接  获取自定义参数
        JobDataMap jdataMap = context.getJobDetail().getJobDataMap();
        JobDataMap tdataMap = context.getTrigger().getJobDataMap();
        String jobMsg = jdataMap.getString("message");
        Float jobFloatValue = jdataMap.getFloat("floatJobValue");
        
        String triMsg = tdataMap.getString("message");
        Double triDoubleValue = tdataMap.getDouble("doubleTriggerValue");
        
        System.out.println("jobMsg is : " + jobMsg);
        System.out.println("jobFloatValue is : " + jobFloatValue);
        System.out.println("triMsg is : " + triMsg);
        System.out.println("triDoubleValue is : " + triDoubleValue);
        
        // 方式一:Map中直接获取 获取自定义参数
        JobDataMap jobDataMap = context.getMergedJobDataMap();
        jobMsg = jobDataMap.getString("message");
        jobFloatValue = jobDataMap.getFloat("floatJobValue");
        
        triMsg = jobDataMap.getString("message");
        triDoubleValue = jobDataMap.getDouble("doubleTriggerValue");
        
        System.out.println("jobMsg is : " + jobMsg);
        System.out.println("jobFloatValue is : " + jobFloatValue);
        System.out.println("triMsg is : " + triMsg);
        System.out.println("triDoubleValue is : " + triDoubleValue);
        
        // 方式二:getter和setter获取
        System.out.println("message is : " + this.message);
        System.out.println("jobFloatValue is : " + this.floatJobValue);
        System.out.println("triDoubleValue is : " + this.doubleTriggerValue);
    }
    
}

2-5 浅谈Trigger

Trigger是什么

Quartz中的触发器用来告诉调度程序作业什么时候触发
即Trigger对象时用来触发执行Job的

Quartz框架中的Trigger示意图

clipboard.png

触发器通用属性

JobKey:表示job实例的标识,触发器被触发时,该指定的job实例会执行
StartTime:表示触发器的时间表首次被触发的时间,它的值的类型是Java.util.Date
EndTime:指定触发器的不再被触发的时间,它的值的类型是Java.util.Date

代码演示

1.HelloJob类改造

package com.myimooc.helloquartz.three;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.Trigger;

/**
 * 自定义任务  触发器通用属性
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloJob implements Job{
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is : " + sf.format(date));
        
        Trigger currentTrigger = context.getTrigger();
        System.out.println("Start Time Is : " + sf.format(currentTrigger.getStartTime()));
        System.out.println("End Time Is : " + sf.format(currentTrigger.getEndTime()));
        
        JobKey jobKey = currentTrigger.getJobKey();
        System.out.println("JobKey info : " + " jobName : " + jobKey.getName()
                + " jobGroup : " + jobKey.getGroup());
    }
    
}

2.HelloScheduler类改造

package com.myimooc.helloquartz.three;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * 任务调度类  触发器通用属性
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloScheduler {
    
    public static void main(String[] args) throws SchedulerException {
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is : " + sf.format(date));
        
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 实例绑定
        JobDetail jobDeatil = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myjob", "jobgroup1")// 定义标识符
                .build();
        
        // 获取距离当前时间3秒后的时间
        date.setTime(date.getTime() + 3000);
        // 获取距离当前时间6秒后的时间
        Date endDate = new Date();
        endDate.setTime(endDate.getTime() + 6000);
        
        // 创建一个 Trigger 实例,定义该 job 立即执行,并且每隔两秒重复执行一次,直到永远
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger","trigroup1")// 定义标识符
                .startAt(date)// 定义3秒后执行
                .endAt(endDate)// 定义6秒后结束
                .withSchedule(SimpleScheduleBuilder
                        .simpleSchedule()
                        .withIntervalInSeconds(2)
                        .repeatForever())// 定义执行频度
                .build();
        
        // 创建 Scheduler 实例
        SchedulerFactory sfact = new StdSchedulerFactory();
        Scheduler scheduler = sfact.getScheduler();
        
        // 绑定 JobDetail 和 trigger
        scheduler.scheduleJob(jobDeatil, trigger);
        
        // 执行任务
        scheduler.start();
    }
    
}

2-6 SimpleTrigger

SimpleTrigger的作用

在一个指定时间段内执行一次作业任务
或是在指定的时间间隔内多次执行作业任务

需要注意的点

重复次数可以为0,正整数或是SimpleTrigger.REPEAT_INDEFINITELY常量值
重复执行间隔必须为0或长整数
一旦被指定了endTime参数,那么它会覆盖重复次数参数的效果

代码演示

1.HelloJob类改造

package com.myimooc.helloquartz.four;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * SimpleTrigger 演示
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloJob implements Job{
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Exec Time Is : " + sf.format(date));
        
        System.out.println("Hello World!");
    }
    
}

2.HelloScheduler类改造

package com.myimooc.helloquartz.four;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

/**
 * SimpleTrigger 演示
 * @author ZhangCheng on 2017-06-26
 *
 */
public class HelloScheduler {
    
    public static void main(String[] args) throws SchedulerException {
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time Is : " + sf.format(date));
        
        // 创建一个 JobDetail 实例,将该实例与 HelloJob 实例绑定
        JobDetail jobDeatil = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myjob", "jobgroup1")// 定义标识符
                .build();
        
        // 获取距离当前时间4秒钟之后的具体时间
        date.setTime(date.getTime() + 4000);
        // 获取距离当前时间6秒钟之后的具体时间
        Date endDate = new Date();
        endDate.setTime(endDate.getTime() + 6000);
        
        // 距离当前时间4秒钟后首次执行任务,之后每隔2秒钟重复执行一次任务
        // 知道距离当前时间6秒钟之后为止
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger","trigroup1")// 定义标识符
                .startAt(date)
                .endAt(endDate)
                .withSchedule(SimpleScheduleBuilder
                        .simpleSchedule()
                        .withIntervalInSeconds(2)
                        .withRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY))
                .build();
         
        // 创建 Scheduler 实例
        SchedulerFactory sfact = new StdSchedulerFactory();
        Scheduler scheduler = sfact.getScheduler();
        scheduler.scheduleJob(jobDeatil, trigger);
        scheduler.start();
    }
    
}

2-7 CronTrigger

CronTrigger的作用

基于日历的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间,比SimpleTrigger更常用

Cron表达式

用于配置CronTrigger实例
是由7个子表达式组成的字符串,描述了时间表的详细信息
格式:[秒][分][小时][日][月][周][年]

Cron表达式特殊字符意义对应表

clipboard.png

特殊符号解释

clipboard.png

Cron表达式举例

clipboard.png

Cron表达式小提示

L和W可以一组合使用
周字段英文字母不区分大小写即MON与mon相同
利用工具,在线生成

2-8 浅谈Scheduler

Scheduler工厂模式

所有的Scheduler实例应该由SchedulerFactory来创建

SchedulerFactory类图

clipboard.png

回顾Quartz三个核心概念

调度器
任务
触发器

示意图

clipboard.png

Scheduler的创建方式

clipboard.png

StdSchedulerFactory

使用一组参数(Java.util.Properties)来创建和初始化Quartz调度器
配置参数一般存储在quartz.properties中
调用getScheduler方法就能创建和初始化调度器对象

Scheduler的主要函数

// 绑定 jobDetail 和 trigger,将它注册进 Scheduler 当中
Date scheduleJob(JobDetail jobDetail, Trigger trigger)
// 启动 Scheduler
void start()
// 暂停 Scheduler
void standby()
// 关闭 Scheduler
void shutdown()

2-9 QuartzProperties文件

quartz.properties组成部分

调度器属性
线程池属性
作业存储设置
插件配置

调度器属性

clipboard.png

线程池属性

threadCount:工作线程数量
threadPriority:工作线程优先级
org.quartz.threadPool.class:配置线程池实现类

作业存储设置

描述了在调度器实例的生命周期中,Job和Trigger信息是如何被存储的

插件配置

满足特定需求用到的Quartz插件的配置

第三章:Spring、Quartz大合体

3-1 搭建工程

基于Maven创建一个简单的SpringMVC工程,学习时,使用springboot框架。

项目POM文件

<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.myimooc</groupId>
  <artifactId>springquartz</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>springquartz</name>
  <url>http://maven.apache.org</url>

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.1.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>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        
        <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  
  <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
</project>

项目目录结构

clipboard.png

3-2 Quartz和Spring大合体

使用Quartz配置作业两种方式

MethodInvokingJobDetailFactoryBean
JobDetailFactoryBean

方式一:使用MethodInvokingJobDetailFactoryBean

1.调用myBean的printMessage方法

clipboard.png

2.MyBean类

clipboard.png

方式二:使用JobDetailFactoryBean

1.需要给作业传递数据,想要更加灵活的话就是用这种方式

clipboard.png

2.FirstScheduleJob类

clipboard.png

3.AnotherBean类

clipboard.png

代码演示:

演示说明:教学基于xml进行配置,学习时基于javaconfig进行配置。

1.编写MyBean类

package com.myimooc.springquartz.quartz;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.stereotype.Component;

/**
 * 方式一:使用MethodInvokingJobDetailFactoryBean 演示
 * @author ZhangCheng on 2017-06-28
 *
 */
@Component
public class MyBean {
    
    public void printMessage(){
        
        // 打印当前的执行时间,格式为2017-01-01 00:00:00
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        System.out.println("MyBean Executes!" + sf.format(date));
    }
    
}

2.编写AnotherBean类

package com.myimooc.springquartz.quartz;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.springframework.stereotype.Component;

/**
 * 方式二:使用JobDetailFactoryBean 演示
 * @author ZhangCheng on 2017-06-28
 *
 */
@Component
public class AnotherBean {
    
    public void printAnotherMessage(){
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        System.out.println("I am AnotherBean." + sf.format(date));
    }
    
}

3.编写FirstScheduledJob类

package com.myimooc.springquartz.quartz;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * 方式二:使用JobDetailFactoryBean 演示
 * @author ZhangCheng on 2017-06-28
 *
 */
public class FirstScheduledJob extends QuartzJobBean {
    
    private AnotherBean anotherBean;
    
    public void setAnotherBean(AnotherBean anotherBean) {
        this.anotherBean = anotherBean;
    }

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        System.out.println("FirstScheduledJob Excutes!" + sf.format(date));
        this.anotherBean.printAnotherMessage();
    }

}

4.编写QuartzConfig类

package com.myimooc.springquartz.config;

import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Trigger;
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.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

import com.myimooc.springquartz.quartz.AnotherBean;
import com.myimooc.springquartz.quartz.FirstScheduledJob;
import com.myimooc.springquartz.quartz.MyBean;

/**
 * Quartz 配置类
 * @author ZhangCheng on 2017-06-28
 *
 */
@Configuration
public class QuartzConfig {
    
    @Autowired
    private MyBean myBean;
    
    @Autowired
    private AnotherBean anotherBean;
    
    /**
     * 方式一:使用MethodInvokingJobDetailFactoryBean
     * @return
     */
    @Bean
    public MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean(){
        MethodInvokingJobDetailFactoryBean mb = new MethodInvokingJobDetailFactoryBean();
        mb.setTargetObject(myBean);// 指定要运行的类
        mb.setTargetMethod("printMessage");// 指定要允许类中的那个方法
        return mb;
    }
    
    /**
     * 方式二:使用JobDetailFactoryBean
     * @return
     */
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean  jb= new JobDetailFactoryBean();
        jb.setJobClass(FirstScheduledJob.class);// 指定要运行的类
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("anotherBean", anotherBean);
        
        jb.setJobDataMap(jobDataMap);// 设置传入自定义参数
        jb.setDurability(true);
        return jb;
    }
    
    /**
     * 配置 SimpleTriggerFactoryBean
     * @return
     */
    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(){
        SimpleTriggerFactoryBean sb = new SimpleTriggerFactoryBean();
        sb.setJobDetail(methodInvokingJobDetailFactoryBean().getObject());// 设置需要绑定的 jobDetail
        sb.setStartDelay(1000L);// 距离当前时间1秒后执行
        sb.setRepeatInterval(2000L);// 之后每隔2秒执行一次
        return sb;
    }
    
    /**
     * 配置 SimpleTriggerFactoryBean
     * @return
     */
    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(){
        CronTriggerFactoryBean cb = new CronTriggerFactoryBean();
        cb.setJobDetail(jobDetailFactoryBean().getObject());// 设置需要绑定的 jobDetail
        cb.setStartDelay(1000L);// 距离当前时间1秒后执行
        cb.setCronExpression("0/5 * * ? * *");// 设置 Cron 表达式,之后每隔5秒执行一次
        return cb;
    }
    
    /**
     * 配置 SchedulerFactoryBean
     * @return
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(){
        SchedulerFactoryBean sb= new SchedulerFactoryBean();
        // 配置 JobDetails
        JobDetail[] jobDetails = new JobDetail[2];
        jobDetails[0] = methodInvokingJobDetailFactoryBean().getObject();
        jobDetails[1] = jobDetailFactoryBean().getObject();
        sb.setJobDetails(jobDetails);
        
        // 配置 Trigger
        Trigger[] triggers = new Trigger[2];
        triggers[0] = simpleTriggerFactoryBean().getObject();
        triggers[1] = cronTriggerFactoryBean().getObject();
        sb.setTriggers(triggers);
        return sb;
        
    }
}

第四章:课程总结

4-1 课程总结

课程回顾

 
Timer
Quartz
Quartz&Spring融合

第五章:Spring boot QuartzConfig另种写法

从上面的例子QuartzConfig中看出autowired中注入了MyBean和AnotherBean。其实可以不用写这个,在方法中写也一样,因为方法中也是注入关系

上面的图就列举了方法注入,同理可得其他,只是方法名称不能乱写,不要一一对应。

下面就列举了2个不同的实例job。

分别创建了2个job,名称分别为JobOneService和JobTwoService

创建QuartzConfig.class

@Configuration
public class QuartzConfig
{
    @Bean("jobOneDetail")
    public MethodInvokingJobDetailFactoryBean jobOneDetailFactoryBean(JobOneService jobOneService)
    {
        MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
        jobDetail.setTargetObject(jobOneService);
        // 是否并发执行
        jobDetail.setConcurrent(true);
        //需要执行的方法-对应JobOneService的方法
        jobDetail.setTargetMethod("task");
        return jobDetail;
    }

    @Bean("jobOneTrigger")
    public SimpleTriggerFactoryBean jobOneTrigger(JobDetail jobOneDetail)
    {
        SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
        trigger.setJobDetail(jobOneDetail);
        trigger.setRepeatCount(0);
        return trigger;
    }

    @Bean("jobTwoDetail")
    public MethodInvokingJobDetailFactoryBean jobTwoDetailFactoryBean(JobTwoService jobTwoService)
    {
        MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
        jobDetail.setTargetObject(jobTwoService);
        // 是否并发执行
        jobDetail.setConcurrent(true);
        //需要执行的方法-对应jobTwoService的方法
        jobDetail.setTargetMethod("task");
        return jobDetail;
    }


    @Bean("jobTwoTrigger")
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetail jobTwoDetail)
    {
        CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
        trigger.setJobDetail(jobTwoDetail);
        // cron表达式,每过10秒执行一次
        trigger.setCronExpression("0/5 * * * * ?");
        return trigger;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(Trigger jobOneTrigger, Trigger jobTwoTrigger)
    {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        // 延时启动,应用启动5秒后
        schedulerFactoryBean.setStartupDelay(5);
        schedulerFactoryBean.setTriggers(jobOneTrigger, jobTwoTrigger);
        return schedulerFactoryBean;
    }
}

1、MethodInvokingJobDetailFactoryBean setTargetMethod 这个就是执行的方法,没有这个都不知道执行什么。

2、看上面的Bean里面的名称都是一一对应的

@Component
@EnableScheduling
public class JobOneService
{
    public void task()
    {
        System.out.println("JobOneService" + new Date());
    }
}

@Component
@EnableScheduling
public class JobTwoService
{
    public void task()
    {
        System.out.println("JobTwoService" + new Date());
    }
}

将任务进行配置,项目启动就会开始执行了。

 
原文地址:https://www.cnblogs.com/zjtao/p/12683790.html