Quartz任务调度框架

使用场景:我们经常在网站上看到一些限时活动,当活动未结束时,活动显示进行时,当活动到达结束日期时我们要将活动设置为已结束,如下图:
这里写图片描述
怎样让程序自动实现这个效果呢
Quartz就是启动定时任务的框架,下载地址:http://www.quartz-scheduler.org/
我们在maven中使用需要导入以下依赖:

<dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz-jobs</artifactId>
        <version>2.2.1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.12</version>
    </dependency>

使用Quartz我们需要掌握三个对象的使用:
1. Scheduler: 定时器,用于管理JobDetail和Trigger。
2. Job: 执行的任务,需要实现org.quartz.Job接口
3. Trigger:触发器,指定任务执行的时间和循环的方式, 什么时间执行, 多久执行一次
触发器有两种:
1. SimpleTrigger: 设置开始时间,设置间隔时间。特点: 间隔时间必须是相同的情况下。
2. CronTrigger: 表达式

Quartz入门

案例一:我们的工作任务是输出一句话:”Hello Quartz!!!”,现在要让这句话每3秒就输出一次;
编写工作任务:

package cn.itcast.demo2;

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

public class HelloJob implements Job{

    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("Hello Quartz!!!");
    }

}

编写定时任务代码(SimpleTrigger):

package cn.itcast.demo1;

import java.util.Date;

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

public class QuartzDemo1{
    public static void main(String[] args) throws SchedulerException {
         //定时器对象
         Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); 
         //定义工作对象
         JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
         //定义触发器
         Trigger tigger = TriggerBuilder.newTrigger().
                 withIdentity("trigger1", "group1").startAt(new Date()).
                 withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3))
                 .build();
         //开启定时任务
         scheduler.scheduleJob(job, tigger);
         scheduler.start(); 
         //关闭定时任务
        // scheduler.shutdown(); 
    }
}

ps:1.对象 TriggerBuilder 启动任务时间
startNow 立即启动
startAt (Date) 指定时间启动
对象 SimpleScheduleBuilder 进行简单任务重复执行
repeatSecondly …() 多少秒后重复执行
repeatminutely …() 多少分钟后重复执行
repeatHourly …() 多少小时后重复执行
2.Job类需要实现Job接口

案例二:按照按照某个时间安排输出:”Hello Quartz!!!”;
CronTrigger的使用:CronTrigger使用较为复杂,主要是表达式的写法:
一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素,分别为:

按顺序依次为
      1  秒(0~59)
      2  分钟(0~59)
      3 小时(0~23)
      4  天(1~31)
      5 月(1~12)
      6  星期(1~7 (1=SUN )或 SUN,MON,TUE,WED,THU,FRI,SAT)
      7.年份(1970-2099),可选

一些通配符的使用:
“*”字符代表所有可能的值
“/”字符用来指定数值的增量
“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值
“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
“W”字符代表着平日(Mon-Fri),并且仅能用于日域中。它用来指定离指定日的最近的一个平日。大部分的商业处理都是基于工作周的,所以 W 字符可能是非常重要的。
“C”代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。
下图列出了个字段能出现的值:
这里写图片描述
下面还有一些我们在工作中可能会用到的表达式:

       0 0 10,14,16 * * ? 每天上午10点,下午2点,40  0/30 9-17  * *  ?  朝九晚五工作时间内每半小时
       0 0 12 ? * WED 表示每个星期三中午12"0 0 12 * * ?" 每天中午12点触发 
       "0 15 10 ? * *" 每天上午10:15触发 
       "0 15 10 * * ?" 每天上午10:15触发 
       "0 15 10 * * ? *" 每天上午10:15触发 
       "0 15 10 * * ? 2005" 2005年的每天上午10:15触发 
       "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 
       "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 
       "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
       "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 
       "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:102:44触发 
       "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 
       "0 15 10 15 * ?" 每月15日上午10:15触发 
       "0 15 10 L * ?" 每月最后一日的上午10:15触发 
       "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 
       "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 
       "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 
       有些子表达式能包含一些范围或列表
       例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”

了解完CronTrigger的表达式后,我们这个案例就很简单了,比如我现在的时间是2018/9/3的20:22分,我需要输出”Hello Quartz!!!”,要求是让这句话在今天20:23分的时候每隔2秒就输出一次,代码如下:

package cn.itcast.demo2;

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

import cn.itcast.demo2.HelloJob;

public class QuartzDemo2{
    public static void main(String[] args) throws SchedulerException {
        // 定时器对象
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        // 定义一个工作对象
        JobDetail job = JobBuilder.newJob(HelloJob.class)
                .withIdentity("job1", "group1").build();
        // 定义触发器
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 23 20 3 9 ?"))
                .build();

        scheduler.scheduleJob(job, trigger);
        // 开启定时任务
        scheduler.start();
    }
}

ps需要注意的点:
day-of-month 和 day-of-week 只能设置一个值,另一个值写 ?
当我们不需要制定年份是,年份一般省略;

**

Quartz整合Spring框架

**
我们在工作中使用Quartz框架往往是整合spring来使用,这样复杂的执行代码就不用我们编写了,我们只需要关心配置:

JobDetialFactoryBean:

<!--job-->
<bean id="exampleJob"
        class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="exampleJob的全类名" />
    </bean>

TriggerFactoryBean:

<!--simpleTrigger-->
<bean id="simpleTrigger"
        class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <property name="jobDetail" ref="exampleJob" />
        <!--程序加载就开始运行-->
        <property name="startDelay" value="0" />
        <!--每1分钟执行一次-->
        <property name="repeatInterval" value="60000" />
    </bean>
<!--cromTrigger-->
<bean id="cronTrigger"
        class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="exampleJob" />
        <!--每天早上6点执行-->
        <property name="cronExpression" value="0 0 6 * * ?" />
    </bean>

SchedulerFactoryBean:

    <!--scheduler-->
        <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobFactory" ref="jobFactory" />
        <property name="triggers">
        <list>
        <ref bean="simpleTrigger"/>
        <ref bean="cronTrigger"/>
        </list>
        </property>
        </bean>

问题:我们在代码中往往是在web层注入service层对象,再调用service层对象执行方法,但是在 Job 中 spring 管理的 Bean 无法注入:

package cn.itcast.quartz.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import cn.itcast.quartz.service.HelloService;

public class HelloJob implements Job{
    @SuppressWarnings("unused")
    @Autowired
    private HelloService helloService;

    public void execute(JobExecutionContext context) throws JobExecutionException {
    //这里会出现空指针异常
        helloService.sayHello();

    }
}

解决: 需要在 Scheduler 中自定义 JobFactory类:

package cn.itcast.quartz.service;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Service;

@Service("jobFactory")
public class JobFactory extends AdaptableJobFactory {

    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle)
            throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }

}

在配置文件中修改:
这里写图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值