JavaEE进阶知识学习-----定时任务调度Quartz学习

本文介绍了Quartz任务调度框架的基本概念、核心组件及其在Spring MVC中的应用。详细讲解了Job、Trigger、Scheduler的工作原理,包括如何配置任务执行的时间、频率等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Quartz简介

Quartz概述

Quartz是一款强大的开源任务调度框架。主要用到了Builder模式,factory模式,组件模式和链式写法。包括了三个核心概念,分别是调度器,任务和触发器。

重要组成部分

Job:实现任务逻辑的任务接口。
JobDetail:JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员变量属性,它用来存储特定Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例。重要的属性如下:name、group、jobClass、jobDataMap。

JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "ground1").build();
System.out.println("jobDetail name:"+jobDetail.getKey().getName());// myJob
System.out.println("jobDetail group:"+jobDetail.getKey().getGroup());//  ground1
System.out.println("jobDetail jobClass:"+jobDetail.getJobClass().getName());// com.study.quartz.HelloJob

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

Quartz的Hello Word

创建maven工程

创建一个maven工程,并引入Quartz的相关jar

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

创建一个job类

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

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

public class HelloJob implements Job{

    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        //打印当前的执行时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        //编写具体的业务逻辑
        System.out.println("Hello World");
    }

}

创建一个Scheduler类

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;

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        // 创建一个JobDetail实例,将实例与HelloJob绑定
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "ground1").build();
        // 创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .startNow()
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInSeconds(2).repeatForever())
                .build();
        //创建Schedule实例
        SchedulerFactory sFactory = new StdSchedulerFactory();
        Scheduler scheduler = sFactory.getScheduler();
        scheduler.start();
        //打印当前时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        scheduler.scheduleJob(jobDetail,trigger);
    }

}

Job中的JobExecutionContext

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

JobDataMap

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

JobDataMap的获取方式

我们修改了HelloScheduler类,并传入了一些我们自定义的参数和值,如何在job中获取这些值,就使用到了JobDataMap对象。

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        // 创建一个JobDetail实例,将实例与HelloJob绑定
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "ground1")
                .usingJobData("message", "Hello job")
                .usingJobData("doubleJobValue", 66.6).build();

        // 创建一个Trigger实例,定义该Job立即执行,并且每隔两秒钟重复执行一次
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .usingJobData("message", "Hello trigger")
                .usingJobData("doubleTrigglerValue", 88.8)
                .startNow()
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInSeconds(2).repeatForever())
                .build();
        //创建Schedule实例
        SchedulerFactory sFactory = new StdSchedulerFactory();
        Scheduler scheduler = sFactory.getScheduler();
        scheduler.start();
        //打印当前时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        scheduler.scheduleJob(jobDetail,trigger);
    }

}

Job类中JobDataMap的获取方式如下,包含了如何获取trigger中的自定义的参数值。

public class HelloJob implements Job{

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //打印当前的执行时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        //编写具体的业务逻辑
        JobKey key = context.getJobDetail().getKey();
        System.out.println("Job的name属性值和group属性值分别为:"+key.getName()+":"+key.getGroup());
        TriggerKey trKey = context.getTrigger().getKey();
        System.out.println("Trigger的name属性值和group属性值分别为:"+trKey.getName()+":"+trKey.getGroup());
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();
        JobDataMap tDataMap = context.getTrigger().getJobDataMap();

        String jobMsg = dataMap.getString("message");
        double doubleJobValue = dataMap.getDouble("doubleJobValue");
        String tiggerMsg = tDataMap.getString("message");
        double doubleTrigglerValue = tDataMap.getDouble("doubleTrigglerValue");
        System.out.println("jobMsg:"+jobMsg);
        System.out.println("doubleJobValue:"+doubleJobValue);
        System.out.println("tiggerMsg:"+tiggerMsg);
        System.out.println("doubleTrigglerValue:"+doubleTrigglerValue);

    }
}

输出结果为:

当前时间为:2018-01-22 17:03:29
Jobname属性值和group属性值分别为:myJob:ground1
Triggername属性值和group属性值分别为:myTrigger:group1
jobMsgHello job
doubleJobValue:66.6
tiggerMsgHello trigger
doubleTrigglerValue:88.8

也可以使用成员变量的getter和setter获取

修改job类的代码如下

public class HelloJob implements Job{
    private String message;
    private double doubleJobValue;
    private double doubleTrigglerValue;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public double getDoubleJobValue() {
        return doubleJobValue;
    }

    public void setDoubleJobValue(double doubleJobValue) {
        this.doubleJobValue = doubleJobValue;
    }

    public double getDoubleTrigglerValue() {
        return doubleTrigglerValue;
    }

    public void setDoubleTrigglerValue(double doubleTrigglerValue) {
        this.doubleTrigglerValue = doubleTrigglerValue;
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //打印当前的执行时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        //编写具体的业务逻辑
        JobKey key = context.getJobDetail().getKey();
        System.out.println("Job的name属性值和group属性值分别为:"+key.getName()+":"+key.getGroup());
        TriggerKey trKey = context.getTrigger().getKey();
        System.out.println("Trigger的name属性值和group属性值分别为:"+trKey.getName()+":"+trKey.getGroup());

        System.out.println("Msg:"+message);
        System.out.println("doubleJobValue:"+doubleJobValue);

        System.out.println("doubleTrigglerValue:"+doubleTrigglerValue);

    }

}

结果为

Job的name属性值和group属性值分别为:myJob:ground1
Trigger的name属性值和group属性值分别为:myTrigger:group1
Msg:Hello trigger
doubleJobValue:66.6
doubleTrigglerValue:88.8

认识Trigger

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

触发器的通用属性

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

实例

HelloScheduler类中的startAt(date)和endAt(endDate)

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        //打印当前时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        // 创建一个JobDetail实例,将实例与HelloJob绑定
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "ground1")
                .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", "group1")
                .startAt(date)//开始执行时间为当前时间的后3秒
                .endAt(endDate)//停止执行的时间为当前时间的后6秒
                .withSchedule(
                        SimpleScheduleBuilder.simpleSchedule()
                                .withIntervalInSeconds(2).repeatForever())
                .build();
        //创建Schedule实例
        SchedulerFactory sFactory = new StdSchedulerFactory();
        Scheduler scheduler = sFactory.getScheduler();
        scheduler.start();
        scheduler.scheduleJob(jobDetail,trigger);
    }

}

HelloJob中获取了开始执行时间和结束执行时间。

public class HelloJob implements Job{

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //打印当前的执行时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        Trigger currentTrigger = context.getTrigger();
        System.out.println("开始时间为:"+currentTrigger.getStartTime());
        System.out.println("结束时间为:"+currentTrigger.getEndTime());
        JobKey  jobKey = currentTrigger.getJobKey();
        System.out.println("jobKeyName:"+jobKey.getName()+"jobGroup:"+jobKey.getGroup());

    }

}

认识SimpleTrigger

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

实例一

距离当前时间4秒后执行且执行一次

public class HelloJob implements Job{

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        //打印当前的执行时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        System.out.println("Hello world");
    }

}

HelloScheduler类中代码如下

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        //打印当前时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:"+sf.format(date));
        // 创建一个JobDetail实例,将实例与HelloJob绑定
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "ground1")
                .build();

        //距离当前时间4秒后执行且执行一次
        date.setTime(date.getTime()+4000);
        SimpleTrigger trigger = (SimpleTrigger)TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .startAt(date)
                .build();
        //创建Schedule实例
        SchedulerFactory sFactory = new StdSchedulerFactory();
        Scheduler scheduler = sFactory.getScheduler();
        scheduler.start();
        scheduler.scheduleJob(jobDetail,trigger);
    }

}

实例二

距距离当前时间4秒后首次执行任务之后每隔两秒重复执行一次,在第一次执行再连续执行三次

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        //打印当前时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:" + sf.format(date));
        // 创建一个JobDetail实例,将实例与HelloJob绑定
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "ground1").build();

        // 距距离当前时间4秒后首次执行任务之后每隔两秒重复执行一次,在第一次执行再连续执行三次
        date.setTime(date.getTime() + 4000);
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .startAt(date)
                .withSchedule(
                        SimpleScheduleBuilder
                                .simpleSchedule()
                                .withIntervalInSeconds(2)
                                .withRepeatCount(3))
                .build();
        // 创建Schedule实例
        SchedulerFactory sFactory = new StdSchedulerFactory();
        Scheduler scheduler = sFactory.getScheduler();
        scheduler.start();
        scheduler.scheduleJob(jobDetail, trigger);
    }

}

实例三

距离当前时间4秒后首次执行,距离当前时间后6秒停止执行

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        //打印当前时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:" + sf.format(date));
        // 创建一个JobDetail实例,将实例与HelloJob绑定
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob", "ground1").build();

        // 距离当前时间4秒后首次执行,距离当前时间后6秒停止执行
        date.setTime(date.getTime() + 4000);
        Date endDate = new Date();
        endDate.setTime(endDate.getTime()+6000);
        SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .startAt(date)
                .endAt(endDate)
                .withSchedule(
                        SimpleScheduleBuilder
                                .simpleSchedule()
                                .withIntervalInSeconds(2)
                                .withRepeatCount(3))
                .build();
        // 创建Schedule实例
        SchedulerFactory sFactory = new StdSchedulerFactory();
        Scheduler scheduler = sFactory.getScheduler();
        scheduler.start();
        scheduler.scheduleJob(jobDetail, trigger);
    }

}

注意

重复次数withRepeatCount:可以是0,正整数或是SimpleTrigger.REPEAT_INDEFINITELY常量值
重复执行间隔withIntervalInSeconds:必须为0或者长整数
指定了endAt参数,就会覆盖重复执行的效果

认识CronTrigger

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

Cron表达式

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

实例一

使用CronTrigger 每秒钟触发一次任务

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
        //打印当前时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("当前时间为:" + sf.format(date));
        // 创建一个JobDetail实例,将实例与HelloJob绑定
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
                .withIdentity("myJob").build();
        // 每秒执行一次任务
        CronTrigger trigger = (CronTrigger) TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "group1")
                .withSchedule(
                        CronScheduleBuilder.cronSchedule("* * * * * ? *"))
                .build();
        // 创建Schedule实例
        SchedulerFactory sFactory = new StdSchedulerFactory();
        Scheduler scheduler = sFactory.getScheduler();
        scheduler.start();
        scheduler.scheduleJob(jobDetail, trigger);
    }

}

注意,表达式中的空格和英文状态

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

Cron表达式举例


实例:

2017年内的每天10点15分触发一次

0 15 10 ? * * 2017

每天的14点整至14点59分55秒,以及18点整至18点59分55秒,每5秒钟触发一次

0/5 * 14,18 * * ?

通配符说明

Cron表达式

  • L和W可以一起使用,例如LW表示每个月的最后一个工作日
  • 周字段英文字母不区分大小写
  • 利用工具,在线生成百度搜索Crona表达式在线生成器

Scheduler-工厂模式

所有的Schedule实例应该有SchedulerFactory来创建,Quartz的三个核心概念是调度器,任务和触发器
关系如下:

Scheduler创建方式

SchedulerFactory sFactory = new StdSchedulerFactory();
Scheduler scheduler = sFactory.getScheduler();

DirectSchedulerFactory factory = DirectSchedulerFactory.getInstance();
Scheduler scheduler2 = factory.getScheduler();

StdSchedulerFactory

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

Scheduler的主要函数

  • Date scheduleJob = scheduler.scheduleJob(jobDetail, trigger);绑定jobDetail和trigger,将它注册进Scheduler中,将trigger中的时间来触发jobDetail中的业务逻辑,返回的时间是最近一次的执行时间。
  • void start();启动Scheduler
  • void standdby();暂停

核心代码

SchedulerFactory sFactory = new StdSchedulerFactory();

Scheduler scheduler = sFactory.getScheduler();

scheduler.start();

scheduler.scheduleJob(jobDetail, trigger);

//scheduler执行两秒后挂起
Thread.sleep(2000L);

scheduler.standby();
//scheduler挂起三秒后重新执行

Thread.sleep(3000L);
scheduler.start();

执行结果为:

当前时间为:2018-01-24 15:25:20
Hello world
当前时间为:2018-01-24 15:25:21
Hello world
当前时间为:2018-01-24 15:25:22
Hello world
当前时间为:2018-01-24 15:25:25
Hello world
当前时间为:2018-01-24 15:25:25
Hello world
当前时间为:2018-01-24 15:25:25
Hello world
当前时间为:2018-01-24 15:25:26
Hello world

void shutdown();关闭

方法中可以传入一个布尔类型的参数,true表示等待所有正在执行的job执行完毕后,再关闭scheduler,false表示直接关闭scheduler。

quartz.properties

项目启动会加载项目根目录下的quartz.properties文件,没有就会加载jar下的quartz.properties文件,文件中的属性如下

  • 调度器属性:org.quartz.scheduler.instanceName属性用来区分特定的调度器实例,可以按照功能用途来给调度器起名。
    org.quartz.scheduler.instanceId属性和前者一样,也允许任何字符串,但是这个值必须在所有调度器实例中是唯一的,尤其在一个集群中,作为集群的唯一key。
  • 线程池属性:重要的属性是threadCount,threadPriority优先值
  • 作业存储设置:描述了调度器实例的生命周期,Job和Trigger信息是如何被存储的。
  • 插件配置:满足特定需求用到的Quartz插件的配置。

quartz.properties文件实例

# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# ===========================================================================
# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.instanceid:AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
# ===========================================================================  
# Configure ThreadPool 线程池属性  
# ===========================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
#指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
org.quartz.threadPool.threadCount: 10
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority: 5
#设置SimpleThreadPool的一些属性
#设置是否为守护线程
#org.quartz.threadpool.makethreadsdaemons = false
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
#org.quartz.threadpool.threadsinheritgroupofinitializingthread=false
#线程前缀默认值是:[Scheduler Name]_Worker
#org.quartz.threadpool.threadnameprefix=swhJobThead;
# 配置全局监听(TriggerListener,JobListener) 则应用程序可以接收和执行 预定的事件通知
# ===========================================================================
# Configuring a Global TriggerListener 配置全局的Trigger监听器
# MyTriggerListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.triggerListener.NAME.class = com.swh.MyTriggerListenerClass
#org.quartz.triggerListener.NAME.propName = propValue
#org.quartz.triggerListener.NAME.prop2Name = prop2Value
# ===========================================================================
# Configuring a Global JobListener 配置全局的Job监听器
# MyJobListenerClass 类必须有一个无参数的构造函数,和 属性的set方法,目前2.2.x只支持原始数据类型的值(包括字符串)
# ===========================================================================
#org.quartz.jobListener.NAME.class = com.swh.MyJobListenerClass
#org.quartz.jobListener.NAME.propName = propValue
#org.quartz.jobListener.NAME.prop2Name = prop2Value
# ===========================================================================  
# Configure JobStore 存储调度信息(工作,触发器和日历等)
# ===========================================================================
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold: 60000
#保存job和Trigger的状态信息到内存中的类
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# ===========================================================================  
# Configure SchedulerPlugins 插件属性 配置
# ===========================================================================
# 自定义插件  
#org.quartz.plugin.NAME.class = com.swh.MyPluginClass
#org.quartz.plugin.NAME.propName = propValue
#org.quartz.plugin.NAME.prop2Name = prop2Value
#配置trigger执行历史日志(可以看到类的文档和参数列表)
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin  
org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}  
org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}  
#配置job调度插件  quartz_jobs(jobs and triggers内容)的XML文档  
#加载 Job 和 Trigger 信息的类   (1.8之前用:org.quartz.plugins.xml.JobInitializationPlugin)
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
#指定存放调度器(Job 和 Trigger)信息的xml文件,默认是classpath下quartz_jobs.xml
org.quartz.plugin.jobInitializer.fileNames = my_quartz_job2.xml  
#org.quartz.plugin.jobInitializer.overWriteExistingJobs = false  
org.quartz.plugin.jobInitializer.failOnFileNotFound = true  
#自动扫描任务单并发现改动的时间间隔,单位为秒
org.quartz.plugin.jobInitializer.scanInterval = 10
#覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
# ===========================================================================  
# Sample configuration of ShutdownHookPlugin  ShutdownHookPlugin插件的配置样例
# ===========================================================================
#org.quartz.plugin.shutdownhook.class = \org.quartz.plugins.management.ShutdownHookPlugin
#org.quartz.plugin.shutdownhook.cleanShutdown = true
#
# Configure RMI Settings 远程服务调用配置
#
#如果你想quartz-scheduler出口本身通过RMI作为服务器,然后设置“出口”标志true(默认值为false)。
#org.quartz.scheduler.rmi.export = false
#主机上rmi注册表(默认值localhost)
#org.quartz.scheduler.rmi.registryhost = localhost
#注册监听端口号(默认值1099)
#org.quartz.scheduler.rmi.registryport = 1099
#创建rmi注册,false/never:如果你已经有一个在运行或不想进行创建注册
# true/as_needed:第一次尝试使用现有的注册,然后再回来进行创建
# always:先进行创建一个注册,然后再使用回来使用注册
#org.quartz.scheduler.rmi.createregistry = never
#Quartz Scheduler服务端端口,默认是随机分配RMI注册表
#org.quartz.scheduler.rmi.serverport = 1098
#true:链接远程服务调度(客户端),这个也要指定registryhost和registryport,默认为false
# 如果export和proxy同时指定为true,则export的设置将被忽略
#org.quartz.scheduler.rmi.proxy = false

Quartz,SpringMVC,Spring

Quartz依赖的包如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
</dependency>

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.3</version>
</dependency>

使用Quartz配置作业的方式

第一种:MethodInvokingJobDetailFactoryBean,在dispatcher-servlet.xml中配置

<bean id="simpleJobDetail"
    class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="myBean" />
    <property name="targetMethod" value="printMessage" />
</bean>

SimpleTrigger的相关配置

<!-- 距离当前时间1秒之后执行,之后每隔两秒钟执行一次 -->
<bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <property name="jobDetail"  ref="simpleJobDetail"/>
    <property name="startDelay"  value="1000"/>
    <property name="repeatInterval"  value="2000"/>
</bean>

其中myBean的相关代码如下

@Component("myBean")
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));
    }
}

第二种:JobDetailFactoryBean,在dispatcher-servlet.xml中配置

<bean id="firstComplexJobDetail"
    class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass"
        value="com.imooc.springquartz.quartz.FirstScheduledJob" />
    <property name="jobDataMap">
        <map>
            <entry key="anotherBean" value-ref="anotherBean" />
        </map>
    </property>
    <property name="Durability" value="true"/>              
</bean>

anotherBean的相关代码如下:

@Component("anotherBean")
public class AnotherBean {
    public void printAnotherMessage() {
        System.out.println("AnotherMessage");
    }
}

FirstScheduledJob类相关代码如下

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 Executes!" + sf.format(date));
        this.anotherBean.printAnotherMessage();     
    }
}

myCronTrigger的相关配置如下

<!-- 每隔5秒钟执行一次 -->
<bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail"  ref="firstComplexJobDetail"/>
    <property name="cronExpression"  value="0/5 * * ? * *"/>
</bean>

两种方法的Scheduler的相关配置

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="jobDetails">
        <list>
            <ref bean="simpleJobDetail"/>
            <ref bean="firstComplexJobDetail"/>
        </list>
    </property>
    <property name="triggers">
        <list>
            <ref bean="mySimpleTrigger"/>
            <ref bean="myCronTrigger"/>
        </list>
    </property>
</bean>

完整项目

dispatcher-servlet.xml文件

<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
            http://www.springframework.org/schema/beans/spring-beans.xsd  
            http://www.springframework.org/schema/mvc  
            http://www.springframework.org/schema/mvc/spring-mvc.xsd  
            http://www.springframework.org/schema/context  
            http://www.springframework.org/schema/context/spring-context.xsd"
    default-lazy-init="true">

    <!-- 通过mvc:resources设置静态资源,这样servlet就会处理这些静态资源,而不通过控制器 -->
    <!-- 设置不过滤内容,比如:css,jquery,img 等资源文件 -->
    <mvc:resources location="/*.html" mapping="/**.html" />
    <mvc:resources location="/css/*" mapping="/css/**" />
    <mvc:resources location="/js/*" mapping="/js/**" />
    <mvc:resources location="/images/*" mapping="/images/**" />
    <!-- 设定消息转换的编码为utf-8防止controller返回中文乱码 -->
    <bean
        class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean
                    class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/html;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
            </list>
        </property>
    </bean>
    <!-- 添加注解驱动 -->
    <mvc:annotation-driven />
    <!-- 默认扫描的包路径 -->
    <context:component-scan base-package="com.imooc.springquartz" />

    <!-- mvc:view-controller可以在不需要Controller处理request的情况,转向到设置的View -->
    <!-- 像下面这样设置,如果请求为/,则不通过controller,而直接解析为/index.jsp -->
    <mvc:view-controller path="/" view-name="index" />
    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
            value="org.springframework.web.servlet.view.JstlView"></property>
        <!-- 配置jsp路径前缀 -->
        <property name="prefix" value="/"></property>
        <!-- 配置URl后缀 -->
        <property name="suffix" value=".jsp"></property>
    </bean>

    <bean id="simpleJobDetail"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myBean" />
        <property name="targetMethod" value="printMessage" />
    </bean>

    <bean id="firstComplexJobDetail"
        class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass"
            value="com.imooc.springquartz.quartz.FirstScheduledJob" />
        <property name="jobDataMap">
            <map>
                <entry key="anotherBean" value-ref="anotherBean" />
            </map>
        </property>
        <property name="Durability" value="true"/>              
    </bean>
    <!-- 距离当前时间1秒之后执行,之后每隔两秒钟执行一次 -->
    <bean id="mySimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <property name="jobDetail"  ref="simpleJobDetail"/>
        <property name="startDelay"  value="1000"/>
        <property name="repeatInterval"  value="2000"/>
    </bean>

    <!-- 每隔5秒钟执行一次 -->
    <bean id="myCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail"  ref="firstComplexJobDetail"/>
        <property name="cronExpression"  value="0/5 * * ? * *"/>
    </bean>

    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobDetails">
            <list>
                <ref bean="simpleJobDetail"/>
                <ref bean="firstComplexJobDetail"/>
            </list>
        </property>
        <property name="triggers">
            <list>
                <ref bean="mySimpleTrigger"/>
                <ref bean="myCronTrigger"/>
            </list>
        </property>
    </bean>
</beans>  

项目结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值