Quartz定时框架搭建——Spring Boot

以下代码亲测可用

定时任务简介

首先定时任务实现方式有无数种,不过最终还是要基于 1、JDK 的Timer类 2、Quartz 3、SpringTask 。这三种方式。但是使用过程中用的最多的便是xml配置的方式,这种方式最简单,无代码侵入,也比较好理解。
但是却有个致命的缺点,比如你要改某个任务的触发时间,亦或是你要新增一个任务,暂停一个任务,那就比较麻烦了,需要停应用!改XML配置!重新启动!
这种方式特别不方便,而且还难受,最近重新研究了下Quartz的基本配置,可以实现定时任务的暂停,添加,删除,立即触发。是不是感觉非常的方便呢。下面看一下Quartz的用法吧!!

Quartz任务调度(Quartz定时任务主要由三部分组成)

  • 首先,依赖是肯定要的,不然没有办法使用
<!-- quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
</dependency>

实现步骤

  • 启动项目,启动task监听

  • 读取数据库,将开启的任务job和trigger加载到scheduler调度器

  • 根据任务调度运行job类

  • 每次运行利用AdaptableJobFactory实例化job类,以便注入要运行的service

听着是不是很简单,直接上代码就明白了

1.Job接口(任务)
Job是定时任务用来实现具体功能的主要接口,可以在里面写想要实现的具体功能,Job接口提供了一个方法叫execute,想要实现Job接口必须实现execute方法,然后把具体的功能代码写入execute方法中,具体代码如下!!!

package com.xb.test.controller.quartz;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.annotation.Resource;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
/**
 * @author XWJ
 *2019年9月19日
 */
@DisallowConcurrentExecution//定时任务不并发 
public class TestJob implements Job{
	public void execute(JobExecutionContext context) {
		try {
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String nowTime=df.format(new Date());
			System.out.println("定时任务测试"+nowTime);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

2.scheduler(调度器)简介
scheduler是Quartz的核心,主要由StdScheduler类、Scheduler接口、StdSchedulerFactory类、SchedulerFactory接口、QuartzScheduler类实现,至于里面具体的源码我们就不看了,有兴趣的可以自己研究一下,scheduler主要的功能是用来对定时任务进行控制的,可以对Job进行添加,删除,修改,暂停,恢复等一系列的控制操作,

3.trigger(触发器)简介
顾名思义,trigger就是用来设置定时任务的触发时间的,里面的具体方法如下表

属性名 属性类型 属性简介
name trigger通用 trigger名称
group trigger通用 trigger所属的组名
description trigger通用 trigger描述
calendarName trigger通用 日历名称,指定使用哪个Calendar类,经常用来从trigger的调度计划中排除某些时间段
misfireInstruction trigger通用 错过job(未在指定时间执行的job)的处理策略,默认为MISFIRE_INSTRUCTION_SMART_POLICY。详见这篇文章
priority trigger通用 优先级,默认为5。当多个trigger同时触发job时,线程池可能不够用,此时根据优先级来决定谁先触发
jobDataMap trigger通用 同job的jobDataMap。假如job和trigger的jobDataMap有同名key,通过getMergedJobDataMap()获取的jobDataMap,将以trigger的为准
startTime trigger通用 触发开始时间,默认为当前时间。决定什么时间开始触发job
endTime trigger通用 触发结束时间。决定什么时间停止触发job
nextFireTime SimpleTrigger私有 下一次触发job的时间
previousFireTime SimpleTrigger私有 上一次触发job的时间
repeatCount SimpleTrigger私有 需触发的总次数
timesTriggered SimpleTrigger私有 已经触发过的次数
repeatInterval SimpleTrigger私有 触发间隔时间
上面这些属性添加完以后都需要生成Trigger实例,这里运用了TriggerBuild,所有的属性最后都通过build保存

4.Quartz主要工具类
这个工具类不需要我们做任何操作,直接使用即可,所有方法的参数都是来自于一个实体类,实体类代码看下面!!

package com.xb.test.controller.quartz;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.DateBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zt.jingcai.entity.TaskDO;
/**
 * @author XWJ
 *2019年9月17日
 */
@Service
public class QuartzManager {
	    @Autowired
	    private Scheduler scheduler;

	    /**
	     * 添加任务
	     * 
	     * @param scheduleJob
	     * @throws SchedulerException
	     */    
	    @SuppressWarnings("unchecked")
	    public void addJob(TaskDO task) {
	        try {
	            // 创建jobDetail实例,绑定Job实现类
	            // 指明job的名称,所在组的名称,以及绑定job类

	            Class<? extends Job> jobClass = (Class<? extends Job>) (Class.forName(task.getBeanClass()).newInstance()
	                    .getClass());
	            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(task.getJobName(), task.getJobGroup())// 任务名称和组构成任务key
	                    .build();
	            // 定义调度触发规则
	            // 使用cornTrigger规则
	            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(task.getJobName(), task.getJobGroup())// 触发器key
	                    .startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
	                    .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression())).startNow().build();
	            // 把作业和触发器注册到任务调度中
	            scheduler.scheduleJob(jobDetail, trigger);
	            // 启动
	            if (!scheduler.isShutdown()) {
	                scheduler.start();
	            }
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }

	    /**
	     * 获取所有计划中的任务列表
	     * 
	     * @return
	     * @throws SchedulerException
	     */
	    public List<TaskDO> getAllJob() throws SchedulerException {
	        GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
	        Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
	        List<TaskDO> jobList = new ArrayList<TaskDO>();
	        for (JobKey jobKey : jobKeys) {
	            List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
	            for (Trigger trigger : triggers) {
	                TaskDO job = new TaskDO();
	                job.setJobName(jobKey.getName());
	                job.setJobGroup(jobKey.getGroup());
	                job.setDescription("触发器:" + trigger.getKey());
	                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
	                job.setJobStatus(triggerState.name());
	                if (trigger instanceof CronTrigger) {
	                    CronTrigger cronTrigger = (CronTrigger) trigger;
	                    String cronExpression = cronTrigger.getCronExpression();
	                    job.setCronExpression(cronExpression);
	                }
	                jobList.add(job);
	            }
	        }
	        return jobList;
	    }

	    /**
	     * 所有正在运行的job
	     * 
	     * @return
	     * @throws SchedulerException
	     */
	    public List<TaskDO> getRunningJob() throws SchedulerException {
	        List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
	        List<TaskDO> jobList = new ArrayList<TaskDO>(executingJobs.size());
	        for (JobExecutionContext executingJob : executingJobs) {
	            TaskDO job = new TaskDO();
	            JobDetail jobDetail = executingJob.getJobDetail();
	            JobKey jobKey = jobDetail.getKey();
	            Trigger trigger = executingJob.getTrigger();
	            job.setJobName(jobKey.getName());
	            job.setJobGroup(jobKey.getGroup());
	            job.setDescription("触发器:" + trigger.getKey());
	            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
	            job.setJobStatus(triggerState.name());
	            if (trigger instanceof CronTrigger) {
	                CronTrigger cronTrigger = (CronTrigger) trigger;
	                String cronExpression = cronTrigger.getCronExpression();
	                job.setCronExpression(cronExpression);
	            }
	            jobList.add(job);
	        }
	        return jobList;
	    }

	    /**
	     * 暂停一个job
	     * 
	     * @param task
	     * @throws SchedulerException
	     */
	    public void pauseJob(TaskDO task) throws SchedulerException {
	        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
	        scheduler.pauseJob(jobKey);
	    }

	    /**
	     * 恢复一个job
	     * 
	     * @param task
	     * @throws SchedulerException
	     */
	    public void resumeJob(TaskDO task) throws SchedulerException {
	        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
	        scheduler.resumeJob(jobKey);
	    }

	    /**
	     * 删除一个job
	     * 
	     * @param task
	     * @throws SchedulerException
	     */
	    public void deleteJob(TaskDO task) throws SchedulerException {
	        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
	        scheduler.deleteJob(jobKey);

	    }

	    /**
	     * 立即执行job
	     * 
	     * @param task
	     * @throws SchedulerException
	     */
	    public void runJobNow(TaskDO task) throws SchedulerException {
	        JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());
	        scheduler.triggerJob(jobKey);
	    }

	    /**
	     * 更新job时间表达式
	     * 
	     * @param task
	     * @throws SchedulerException
	     */
	    public void updateJobCron(TaskDO task) throws SchedulerException {

	        TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName(), task.getJobGroup());

	        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

	        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCronExpression());

	        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

	        scheduler.rescheduleJob(triggerKey, trigger);
	    }
	}

5.Job service注入问题
光上面这些还是不够,Job在实例化过程中是在Quartz中进行的,这时候我们将spring的东西注入进来,肯定是行不通的,所以需要这个类,如果想在Job里面进行注入操作就必须添加下面这个工具类!!

/**
 * 
 */
package com.xb.test.controller.quartz;

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.Component;

/**
 * @author XWJ
 *2019年9月17日
 */
@Component
public class JobFactory extends AdaptableJobFactory {
    //这个对象Spring会帮我们自动注入进来,.
    //为什么需要这个类呢,在我写的这个demo中,大家可以将此类删掉,发现程序也可以政策运营,可是我为什么还是加上呢。
    //大家可以看下我们的任务类,大家可以看到Job对象的实例化过程是在Quartz中进行的,这时候我们将spring的东西注入进来,肯定是行不通的,所以需要这个类
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        //进行注入
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

6.实体类代码

package com.zt.jingcai.entity;

import java.io.Serializable;
import java.util.Date;

public class TaskDO implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private Long id;
    // 任务名
    private String jobName;
    // 任务描述
    private String description;
    // cron表达式(不会写,百度可以搜到)
    private String cronExpression;
    // 任务执行时调用哪个类的方法 包名+类名
    private String beanClass;
    // 任务状态
    private String jobStatus;
    // 任务分组
    private String jobGroup;

    private String createUser;

    private Date createTime;

    private String updateUser;

    private Date updateTime;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getJobName() {
        return jobName;
    }

    public void setJobName(String jobName) {
        this.jobName = jobName == null ? null : jobName.trim();
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description == null ? null : description.trim();
    }

    public String getCronExpression() {
        return cronExpression;
    }

    public void setCronExpression(String cronExpression) {
        this.cronExpression = cronExpression == null ? null : cronExpression.trim();
    }

    public String getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(String beanClass) {
        this.beanClass = beanClass == null ? null : beanClass.trim();
    }

    public String getJobStatus() {
        return jobStatus;
    }

    public void setJobStatus(String jobStatus) {
        this.jobStatus = jobStatus == null ? null : jobStatus.trim();
    }

    public String getJobGroup() {
        return jobGroup;
    }

    public void setJobGroup(String jobGroup) {
        this.jobGroup = jobGroup == null ? null : jobGroup.trim();
    }

    public String getCreateUser() {
        return createUser;
    }

    public void setCreateUser(String createUser) {
        this.createUser = createUser == null ? null : createUser.trim();
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public String getUpdateUser() {
        return updateUser;
    }

    public void setUpdateUser(String updateUser) {
        this.updateUser = updateUser == null ? null : updateUser.trim();
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
}

7.任务调度的具体代码(我这个是测试的你们可以参考)

/**
 * 
 */
package com.xb.test.controller.quartz;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.zt.jingcai.entity.TaskDO;




/**
 * @author XWJ
 *2019年9月17日
 */
@Component
public class JobTaskScheduling {
	
	  @Autowired 
	  private QuartzManager quartzManager;
	 
	
	@PostConstruct
	void UserClockRemindedTask() {
		try {
			TaskDO task = new TaskDO();
			task.setJobName("userClockRemindedJob");
			task.setDescription("用户每日打卡提醒");
			task.setCronExpression("0 0/9 * * * ?");
			task.setBeanClass("com.xb.test.controller.quartz.TestJob");
			quartzManager.addJob(task);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

  • 这样,一个完整的定时任务调度框架就搭建完了,如果想要把Quartz定时任务框架做成持久层的,参考【SpringBoot整合Quartz框架完成定时任务的持久化操作】,以上内容个人亲测可用,如有问题,还请指出,最后看都看了,码字不易,顺手点个赞呗!!

你可能感兴趣的:(Quartz定时框架搭建——Spring Boot)