Quartz定时任务框架使用

先看这个

Quartz最重要的3个基本要素:

  • Scheduler:调度器。所有的调度都是由它控制。
  • Trigger: 定义触发的条件。
  • Job: 要执行的任务

也就是弄好这三个就可以了,一个调度器,一个任务,一个触发器,最后把任务跟触发器放到调度器里面执行就可以了

话不多说,直接先演示一个简单的栗子

前提:创建一个spring boot项目,层级结构如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IDtWB5MA-1653205346491)(D:\中兴java\笔记  陈嘉伟\quartz框架\pic\333333.png)]

1、创建一个job类,实现Job接口,里面是具体要执行的任务

package com.cjw.sbptquartz.myJob;

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

public class ChapterJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("我在工作········");
    }
}

2、执行6个步骤开始任务

package com.cjw.sbptquartz.service.impl;

import com.cjw.sbptquartz.mapper.QuartzMapper;
import com.cjw.sbptquartz.model.EduChapter;
import com.cjw.sbptquartz.myJob.ChapterJob;
import com.cjw.sbptquartz.service.QuartzService;
import com.cjw.sbptquartz.utils.QuartzManager;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

@Service
public class QuartzServiceImpl implements QuartzService {

    @Autowired
    private QuartzManager quartzManager;

    @Override
    public void quartzTest() {
        try {
            //1、先实例化调度器工厂
            SchedulerFactory factory = new StdSchedulerFactory();
            //2、得到调度器
            Scheduler scheduler = factory.getScheduler();
            //3、创建任务
            JobDetail jobDetail = newJob(ChapterJob.class)
                    .withDescription("这是我第一个任务")
                    .withIdentity("a", "b")//定义name/group,区分每个job
                    .build();

            //4.创建触发器
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withDescription("触发器")
                    .withIdentity("b", "c")
                    .startAt(new Date())
                    .withSchedule(
                            simpleSchedule()
                                    .withIntervalInSeconds(1)	//间隔1秒
                                    .repeatForever()		//一直循环
                    )
                    .build();
            //5.将触发器和任务绑定到调度器中去
            scheduler.scheduleJob(jobDetail, trigger);
            //6.启动调度器
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        } finally {
        }
    }
}

在这里插入图片描述

usingJobData

JobDetail和Trigger都可以定义自己的一些map数据集合,在job中可以拿到。
在上面的QuartzServiceImpl类中稍微加一点

            //3、创建任务
            JobDetail jobDetail = newJob(ChapterJob.class)
                    .withDescription("这是我第一个任务")
                    .withIdentity("a", "b")//定义name/group,区分每个job
                    .usingJobData("nameJob", "王阿姨")//定义属性,传参到job中
                    .build();

            //4.创建触发器
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withDescription("大扫除触发器")
                    .withIdentity("b", "c")
                    .usingJobData("nameTri","嗯嗯")//定义属性,传参到job中
                    .startAt(new Date())
                    .withSchedule(
                            simpleSchedule()
                                    .withIntervalInSeconds(1)
                                    .repeatForever()
                    )
                    .build();

在上面的ChapterJob类中稍微加一点

package com.zte.sbptquartz.myJob;

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

public class ChapterJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//        Object name = jobExecutionContext.getJobDetail().getJobDataMap().get("name");
//        Object name1 = jobExecutionContext.getJobDetail().getJobDataMap().get("a");
//        System.out.println("name======="+name);
//        System.out.println("a======="+name1);

        System.out.println("我在工作········");

        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); //jobDetail的
        JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();//trigger的
        //还可以两个map数据集合并,但是如果有相同的会被覆盖
        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();

        String nameJob = jobDataMap.getString("nameJob");//王阿姨
        String nameTri = triggerDataMap.getString("nameTri");//嗯嗯
        String nameJob1 = mergedJobDataMap.getString("nameJob");//王阿姨
        System.out.println(nameJob);
        System.out.println(nameTri);
        System.out.println(nameJob1);
    }
}

String nameJob = jobDataMap.getString(“nameJob”);//王阿姨
String nameTri= triggerDataMap.getString(“nameTri”);//嗯嗯
String nameJob1 = mergedJobDataMap.getString(“nameJob”);//王阿姨

如果每个值都要这么取会比较麻烦,还有一种办法,定义name属性实现set方法,框架会自动装进去

package com.zte.sbptquartz.myJob;

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

public class ChapterJob implements Job {

    private String nameJob;
    private String nameTri;

    public void setNameJob(String nameJob) {
        this.nameJob = nameJob;
    }

    public void setNameTri(String nameTri) {
        this.nameTri = nameTri;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        System.out.println("我在工作········");

        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap(); //jobDetail的
        JobDataMap triggerDataMap = jobExecutionContext.getTrigger().getJobDataMap();//trigger的
        //还可以两个map数据集合并,但是如果有相同的会被覆盖
        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();

 //       String nameJob = jobDataMap.getString("nameJob");//王阿姨
 //       String nameTri = triggerDataMap.getString("nameTri");//嗯嗯
 //       String nameJob1 = mergedJobDataMap.getString("nameJob");//王阿姨
        System.out.println(nameJob);
        System.out.println(nameTri);
    }
}

JobDetail

//3、创建任务
JobDetail jobDetail = newJob(ChapterJob.class)
        .withDescription("这是我第一个任务")
        .withIdentity("a", "b")//定义name/group,区分每个job
        .usingJobData("nameJob", "王阿姨")//定义属性,传参到job中
        .build();

在循环执行任务的过程中,每次执行一次任务JobDetail都是一个新的实例,这样做的目的是防止并发访问。

但是有些业务是需要控制下一次执行的开始是上一次执行的结束,好办,加个注解,禁止并发执行。

@DisallowConcurrentExecution
public class ChapterJob implements Job {

还有一个注解了解一下

@PersistJobDataAfterExecution:告诉Quartz在成功执行了Job实现类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据,使得该JobDetail实例在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。

Trigger

触发器有 SimpleTrigger 和 CronTrigger,上面用的就是SimpleTrigger

simpleTrigger触发器是为那种需要在特定日期/时间启动,且以一个可能的间隔时间重复执行N次的Job所设计的。

cronTrigger触发器可以像日历那样按日程触发任务,是一个基于日历的作业调度器,它有Cron表达式:用来配置CronTrigger实例,由7个部分组成,每个部分就如图所示分别对应秒 分 一直到年。(表达式生成的网站https://qqe2.com/cron)

SimpleTrigger 实例:

 //4.创建触发器
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withDescription("大扫除触发器")
                    .withIdentity("b", "c")
                    .usingJobData("nameTri","嗯嗯")
                    .startAt(new Date())
                	.startNow()//一旦加入scheduler,立即生效
                    .withSchedule(
                            SimpleScheduleBuilder.simpleSchedule()
                                    .withIntervalInSeconds(1)//一秒一次
                                    .withIntervalInHours(1)//一小时一次
//                                    .repeatForever()  //一直重复
                                    .withRepeatCount(2)//重复几次
                    )
                    .build();

CronTrigger实例:

 		//触发器(Trigger)
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "group1")  //定义该触发器的唯一标识
                .startAt(new Date())  //开始时间
            	.startNow()//一旦加入scheduler,立即生效
                .withSchedule(CronScheduleBuilder.cronSchedule("30 * * * * ?"))//CronTrigger 在此定义表达式:每分钟的第30秒触发一次
            	.WithCronSchedule("0 0/30 8-20 * * ?")//每天8-20点,每半个小时执行一次(即8:00、8:30  。。。。   19:30、20:30)
            	.WithCronSchedule("0 0 2 ? * Mon-Fri")//每个工作日的凌晨2点执行1次
            	.WithCronSchedule("0 0 2 ? * Mon,Wes")//每个周的周一和周四的2点执行1次
                .build();

QuartzManager

为了方便管理,可以弄成一个定时器管理类

package com.zte.sbptquartz.utils;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 定时器管理
 */
public class QuartzManager {

    private static Logger logger = LoggerFactory.getLogger(QuartzManager.class);

    private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();

    /**
     * @param jobName          任务名
     * @param jobGroupName     任务组名
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param jobClass         任务
     * @param cron             时间设置,参考quartz说明文档
     * @Description: 添加一个定时任务
     */
    public static void addJob(String jobName, String jobGroupName,
                              String triggerName, String triggerGroupName, Class jobClass, String cron) {
        try {
            Scheduler sched = schedulerFactory.getScheduler();
            // 任务名,任务组,任务执行类
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();

            // 触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(triggerName, triggerGroupName);
            triggerBuilder.startNow();
            // 触发器时间设定
            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
            // 创建Trigger对象
            CronTrigger trigger = (CronTrigger) triggerBuilder.build();

            // 调度容器设置JobDetail和Trigger
            sched.scheduleJob(jobDetail, trigger);

            // 启动
            if (!sched.isShutdown()) {
                sched.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * @param triggerName      触发器名
     * @param triggerGroupName 触发器组名
     * @param cron             时间设置,参考quartz说明文档
     * @Description: 修改一个任务的触发时间
     */
    public static void modifyJobTime(String triggerName, String triggerGroupName, String cron) {
        try {
            Scheduler sched = schedulerFactory.getScheduler();
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
            CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
            if (trigger == null) {
                return;
            }

            String oldTime = trigger.getCronExpression();
            if (!oldTime.equalsIgnoreCase(cron)) {
                /** 方式一 :调用 rescheduleJob 开始 */
                // 触发器
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(triggerName, triggerGroupName);
                triggerBuilder.startNow();
                // 触发器时间设定
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
                // 创建Trigger对象
                trigger = (CronTrigger) triggerBuilder.build();
                // 方式一 :修改一个任务的触发时间
                sched.rescheduleJob(triggerKey, trigger);
                /** 方式一 :调用 rescheduleJob 结束 */

                /** 方式二:先删除,然后在创建一个新的Job  */
                //JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
                //Class<? extends Job> jobClass = jobDetail.getJobClass();
                //removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
                //addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
                /** 方式二 :先删除,然后在创建一个新的Job */
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param jobName
     * @param jobGroupName
     * @param triggerName
     * @param triggerGroupName
     * @Description: 移除一个任务
     */
    public static void removeJob(String jobName, String jobGroupName,
                                 String triggerName, String triggerGroupName) {
        try {
            Scheduler sched = schedulerFactory.getScheduler();

            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);

            sched.pauseTrigger(triggerKey);// 停止触发器
            sched.unscheduleJob(triggerKey);// 移除触发器
            sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @Description:启动所有定时任务
     */
    public static void startJobs() {
        try {
            Scheduler sched = schedulerFactory.getScheduler();
            sched.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @Description:关闭所有定时任务
     */
    public static void shutdownJobs() {
        try {
            Scheduler sched = schedulerFactory.getScheduler();
            if (!sched.isShutdown()) {
                sched.shutdown();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 安全关闭
     *
     * @throws SchedulerException
     */
    public static void safeShutdown() throws SchedulerException {
        Scheduler scheduler = schedulerFactory.getScheduler();
        int executingJobSize = scheduler.getCurrentlyExecutingJobs().size();
        logger.info("安全关闭 当前还有" + executingJobSize + "个任务正在执行,等待完成后关闭");
        //等待任务执行完后安全关闭
        scheduler.shutdown(true);

        logger.info("安全关闭 成功");
    }
}

示范

public void testGetJobState(){
        try {
            QuartzManager.addJob("jobnamee1","jobgroupp1",
                    "trinamee1","trigroupp1",
                    ChapterJob1.class,"0/1 * * * * ? *");//这行代码就已经启动了定时器,每秒执行一次
            //cron表达式可以去https://qqe2.com/cron生成
            
            QuartzManager1.removeJob("jobnamee","jobgroupp",
                    "trinamee","trigroupp");//移除任务
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值