一. 引入依赖
<!-- 引入quartz依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
二. Quartz配置类
package com.example.demo.quartztask;
import org.quartz.JobDetail;
import org.quartz.spi.JobFactory;
import org.springframework.context.ApplicationContext;
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.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SpringBeanJobFactory; import java.io.IOException; /** * @program: demo * @description: quartz动态定时任务配置类 * @author: guoxu * @create: 2019-12-31 09:43 */ @Configuration public class SchedulerConfig { @Bean public JobFactory jobFactory(ApplicationContext applicationContext) { SpringBeanJobFactory jobFactory = new SpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; } /**调度工厂bean * @param jobFactory * @throws IOException */ @Bean public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws IOException { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setJobFactory(jobFactory); //QuartzScheduler 延时启动,应用启动完5秒后 QuartzScheduler 再启动 factory.setStartupDelay(5); // this allows to update triggers in DB when updating settings in config file: //用于quartz集群,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 // factory.setOverwriteExistingJobs(true); //用于quartz集群,加载quartz数据源 // factory.setDataSource(dataSource); //用于quartz集群,加载quartz数据源配置 // factory.setQuartzProperties(quartzProperties()); //注册触发器 //factory.setTriggers(cronJobTrigger); return factory; } /**加载quartz数据源配置,quartz集群时用到 * @return * @throws IOException */ // @Bean // public Properties quartzProperties() throws IOException { // PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean(); // propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties")); // propertiesFactoryBean.afterPropertiesSet(); // return propertiesFactoryBean.getObject(); // } /** * 创建触发器工厂 * @param jobClass * @return */ private static JobDetailFactoryBean createJobDetail(Class jobClass) { JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); factoryBean.setJobClass(jobClass); factoryBean.setDurability(true); return factoryBean; } /**创建定时器工厂 * @param jobDetail * @return */ private static CronTriggerFactoryBean createTrigger(JobDetail jobDetail) { CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); factoryBean.setJobDetail(jobDetail); factoryBean.setStartDelay(0L); factoryBean.setCronExpression ("0/5 * * * * ? ");//每5秒执行一次 return factoryBean; } }
三. MgrScheduleJob定时任务实体类
数据库SQL:
CREATE TABLE `t_schedule_job` (
`ID` char(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '任务主键', `TASK_NAME` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务名称', `TASK_GROUP` char(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务分组', `CLASS_NAME` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'class类名称地址', `DESCRIPTION` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任务描述', `CRON_EXPRESSION` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '时间设置(定时器时间格式)', `TASK_STATUS` int(1) NULL DEFAULT NULL COMMENT '0: 执行 1: 暂停', `IS_ENABLE` int(1) NULL DEFAULT NULL COMMENT '0:启用 1:停用', `UPDATE_TIME` datetime(6) NULL DEFAULT NULL COMMENT '更新时间', `CREATE_TIME` datetime(6) NULL DEFAULT NULL COMMENT '创建时间', `CREATE_USER` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '创建人', PRIMARY KEY (`ID`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
实体类:
package com.example.demo.domin;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor; import org.nutz.dao.entity.annotation.*; import java.io.Serializable; import java.util.Date; /** * @Description * @Author GuoXu * @Date 2019-12-31 */ @Data @Builder @AllArgsConstructor @NoArgsConstructor @Table ( "t_schedule_job" ) public class MgrScheduleJob implements Serializable { private static final long serialVersionUID = 515061450646512139L; /** * 任务主键 */ @Name @Prev(els = @EL("uuid(32)")) @Column("ID" ) private String id; /** * 任务名称 */ @Column("TASK_NAME" ) private String taskName; /** * 任务分组 */ @Column("TASK_GROUP" ) private String taskGroup; /** * class类名称地址 */ @Column("CLASS_NAME" ) private String className; /** * 任务描述 */ @Column("DESCRIPTION") private String description; /** * 时间设置(定时器时间格式) */ @Column("CRON_EXPRESSION" ) private String cronExpression; /** * 0:执行 1:暂停 */ @Column("TASK_STATUS" ) private Integer taskStatus; /** * 0:启用 1:停用 */ @Column("IS_ENABLE") private Integer isEnable; /** * 更新时间 */ @Column("UPDATE_TIME" ) private Date updateTime; /** * 创建时间 */ @Column("CREATE_TIME" ) private Date createTime; /** * 创建人 */ @Column("CREATE_USER" ) private String createUser; }
四. Quartz定时任务方法类
这里是为了更好的区分业务逻辑,故分为定时任务基础方法类,和定时任务控制实现方法类
以下的IBaseService和BaseService类,是基于nutzDao的curd方法进行了再封装,想详细了解的可以看我的另外一篇文章
接口:
package com.example.demo.quartztask;
import com.example.demo.base.IBaseService;
import com.example.demo.domin.MgrScheduleJob;
import org.quartz.SchedulerException;
import java.util.List; /** * @program: demo * @description: quartz定时任务Service * @author: guoxu * @create: 2019-12-31 10:21 */ public interface IJobAndTriggerService extends IBaseService<MgrScheduleJob> { /** * 新增任务 * @param scheduleJob * @throws Exception */ void addOrUpdateJob(MgrScheduleJob scheduleJob) throws Exception; /** * Scheduler 删除定时任务 * @param scheduleJob * @throws Exception */ void stopJob(MgrScheduleJob scheduleJob) throws SchedulerException; /** * Scheduler 暂停定时任务 * @param scheduleJob * @throws Exception */ void pauseJob(MgrScheduleJob scheduleJob) throws SchedulerException; /** * Scheduler 恢复定时任务 * @param scheduleJob * @throws Exception */ void resumejob(MgrScheduleJob scheduleJob) throws SchedulerException; /** * 立即执行一个job * @param scheduleJob * @throws SchedulerException */ void runAJobNow(MgrScheduleJob scheduleJob) throws SchedulerException; /** * 获取所有计划中的任务列表 * @return * @throws SchedulerException */ List<MgrScheduleJob> getAllJob() throws SchedulerException; /** * 获取所有执行中的任务列表 * @return * @throws SchedulerException */ List<MgrScheduleJob> getRunningJob() throws SchedulerException; /** * 暂停所有任务 * @throws SchedulerException */ void pauseAllJobs() throws SchedulerException; /** * 恢复所有任务 * @throws SchedulerException */ void resumeAllJobs() throws SchedulerException; }
实现:
package com.example.demo.quartztask;
import com.example.demo.base.BaseServiceImpl;
import com.example.demo.domin.MgrScheduleJob;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd; import org.quartz.*; import org.quartz.impl.matchers.GroupMatcher; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * @program: demo * @description: quartz定时任务实现类 * @author: guoxu * @create: 2019-12-31 10:45 */ /** * Scheduler:调度器,进行任务调度;quartz的大脑 * Job:业务job,亦可称业务组件;定时任务的具体执行业务需要实现此接口,调度器会调用此接口的execute方法完成我们的定时业务 * JobDetail:用来定义业务Job的实例,我们可以称之为quartz job,很多时候我们谈到的job指的是JobDetail * Trigger:触发器,用来定义一个指定的Job何时被执行 * JobBuilder:Job构建器,用来定义或创建JobDetail的实例;JobDetail限定了只能是Job的实例 * TriggerBuilder:触发器构建器,用来定义或创建触发器的实例 */ @Slf4j @Service public class JobAndTriggerServiceImpl extends BaseServiceImpl<MgrScheduleJob> implements IJobAndTriggerService{ @Autowired private SchedulerFactoryBean schedulerFactoryBean; /** * 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。 * @throws Exception */ @PostConstruct public void init() { // 这里获取任务信息数据 List<MgrScheduleJob> jobList = nutzDao.query(MgrScheduleJob.class, Cnd.where("isEnable", "=", 0)); jobList.forEach(job -> { try { if (job.getTaskStatus() == 1){ job.setTaskStatus(0); nutzDao.update(job); } addOrUpdateJob(job); } catch (Exception e) { e.printStackTrace(); log.error("初始化定时任务列表异常->{}",e.getMessage()); } }); } @Override public void addOrUpdateJob(MgrScheduleJob mgrScheduleJob) throws Exception { //获去调度器实例 Scheduler scheduler = schedulerFactoryBean.getScheduler(); TriggerKey triggerKey = TriggerKey.triggerKey(mgrScheduleJob.getTaskName(), mgrScheduleJob.getTaskGroup()); CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); //trigger不存在,创建一个 if (null == trigger) { //新增定时任务 Class clazz = Class.forName(mgrScheduleJob.getClassName()); //判断clazz是否为null,是则抛出异常 Assert.notNull(clazz, "定时任务执行类为NULL"); //初始化一个类,生成一个实例 clazz.newInstance(); // 构建job信息 JobDetail jobDetail = JobBuilder.newJob(clazz) .withIdentity(mgrScheduleJob.getTaskName(),mgrScheduleJob.getTaskGroup()).build(); // 表达式调度构建器(即任务执行的时间) CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(mgrScheduleJob.getCronExpression()); // 按新的cronExpression表达式构建一个新的trigger trigger = TriggerBuilder.newTrigger().withIdentity(mgrScheduleJob.getTaskName(),mgrScheduleJob.getTaskGroup()) .withSchedule(scheduleBuilder).build(); //设置job执行 scheduler.scheduleJob(jobDetail, trigger); } else { // Trigger已存在,那么更新相应的定时设置 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(mgrScheduleJob.getCronExpression()); // 按新的cronExpression表达式重新构建trigger trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); // 按新的trigger重新设置job执行 scheduler.rescheduleJob(triggerKey, trigger); } } @Override public void stopJob(MgrScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getTaskName(), scheduleJob.getTaskGroup()); scheduler.deleteJob(jobKey); } @Override public void pauseJob(MgrScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getTaskName(), scheduleJob.getTaskGroup()); scheduler.pauseJob(jobKey); } @Override public void resumejob(MgrScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getTaskName(), scheduleJob.getTaskGroup()); scheduler.resumeJob(jobKey); } @Override public void runAJobNow(MgrScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getTaskName(), scheduleJob.getTaskGroup()); scheduler.triggerJob(jobKey); } @Override public List<MgrScheduleJob> getAllJob() throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); List<MgrScheduleJob> jobList = new ArrayList<MgrScheduleJob>(); GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup(); Set<JobKey> jobKeys = scheduler.getJobKeys(matcher); jobKeys.forEach(jobKey -> { List<? extends Trigger> triggers = null; try { triggers = scheduler.getTriggersOfJob(jobKey); } catch (SchedulerException e) { e.printStackTrace(); } if (triggers != null) { triggers.forEach(trigger -> { MgrScheduleJob job = new MgrScheduleJob(); job.setTaskName(jobKey.getName()); job.setTaskGroup(jobKey.getGroup()); if (trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; String cronExpression = cronTrigger.getCronExpression(); job.setCronExpression(cronExpression); } jobList.add(job); }); } }); return jobList; } @Override public List<MgrScheduleJob> getRunningJob() throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs(); List<MgrScheduleJob> jobList = new ArrayList<MgrScheduleJob>(executingJobs.size()); for (JobExecutionContext executingJob : executingJobs) { MgrScheduleJob job = new MgrScheduleJob(); JobDetail jobDetail = executingJob.getJobDetail(); JobKey jobKey = jobDetail.getKey(); job.setTaskName(jobKey.getName()); job.setTaskGroup(jobKey.getGroup()); Trigger trigger = executingJob.getTrigger(); // Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); if (trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; String cronExpression = cronTrigger.getCronExpression(); job.setCronExpression(cronExpression); } jobList.add(job); } return jobList; } @Override public void pauseAllJobs() throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); scheduler.pauseAll(); } @Override public void resumeAllJobs() throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); scheduler.resumeAll(); } }
五. MgrScheduleJob定时任务控制Service类
接口:
package com.example.demo.quartztask;
import com.example.demo.base.IBaseService;
import com.example.demo.domin.MgrScheduleJob;
/**
* @program: demo * @description: 定时任务实体Service类 * @author: guoxu * @create: 2019-12-31 14:48 */ public interface IScheduleJobService extends IBaseService<MgrScheduleJob> { /** * 添加或新增定时任务 * @param mgrScheduleJob * @throws Exception */ void addOrUpdateScheduleJob(MgrScheduleJob mgrScheduleJob) throws Exception; /** * 修改定时任务启用状态 0 启用 1 停用 * @param id * @throws Exception */ void isEnableScheduleJob(String id) throws Exception; /** * 暂停/恢复 定时任务 * @param id * @throws Exception */ void pauseScheduleJob(String id) throws Exception; /** * 删除定时任务 * @param id * @throws Exception */ void deleteScheduleJob(String id) throws Exception; /** * 立即运行定时任务 * @param id * @throws Exception */ void runScheduleJob(String id) throws Exception; }
实现:
package com.example.demo.quartztask;
import com.example.demo.base.BaseServiceImpl;
import com.example.demo.domin.MgrScheduleJob;
import com.example.demo.utils.StringUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; /** * @program: demo * @description: 定时任务Service实现类 * @author: guoxu * @create: 2019-12-31 15:17 */ @Service public class ScheduleJobServiceImpl extends BaseServiceImpl<MgrScheduleJob> implements IScheduleJobService { @Autowired private IJobAndTriggerService jobAndTriggerService; @Override public void addOrUpdateScheduleJob(MgrScheduleJob mgrScheduleJob) throws Exception { if (StringUtil.isNotEmpty(mgrScheduleJob.getId())){ //更新任务 mgrScheduleJob.setTaskStatus(0); mgrScheduleJob.setIsEnable(0); mgrScheduleJob.setUpdateTime(new Date()); update(mgrScheduleJob); }else { //新增任务 mgrScheduleJob.setTaskStatus(0); mgrScheduleJob.setIsEnable(0); mgrScheduleJob.setCreateTime(new Date()); mgrScheduleJob.setUpdateTime(new Date()); add(mgrScheduleJob); } jobAndTriggerService.addOrUpdateJob(mgrScheduleJob); } @Override public void isEnableScheduleJob(String id) throws Exception { MgrScheduleJob mgrScheduleJob = load(id); if (mgrScheduleJob.getIsEnable() == 0){ //停用任务 mgrScheduleJob.setIsEnable(1); update(mgrScheduleJob); jobAndTriggerService.stopJob(mgrScheduleJob); }else if (mgrScheduleJob.getIsEnable() == 1){ //启用任务 mgrScheduleJob.setIsEnable(0); update(mgrScheduleJob); jobAndTriggerService.addOrUpdateJob(mgrScheduleJob); } } @Override public void pauseScheduleJob(String id) throws Exception { MgrScheduleJob mgrScheduleJob = load(id); if (mgrScheduleJob.getTaskStatus() == 0){ //暂停任务 mgrScheduleJob.setTaskStatus(1); update(mgrScheduleJob); jobAndTriggerService.pauseJob(mgrScheduleJob); }else if (mgrScheduleJob.getTaskStatus() == 1){ //执行任务 mgrScheduleJob.setTaskStatus(0); update(mgrScheduleJob); jobAndTriggerService.resumejob(mgrScheduleJob); } } @Override public void deleteScheduleJob(String id) throws Exception { MgrScheduleJob mgrScheduleJob = load(id); jobAndTriggerService.stopJob(mgrScheduleJob); deleteById(id); } @Override public void runScheduleJob(String id) throws Exception { jobAndTriggerService.runAJobNow(load(id)); } }
六. 定时任务控制接口调用ScheduleJobController
package com.example.demo.quartztask;
import com.example.demo.domin.MgrScheduleJob;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; /** * @program: demo * @description: 定时任务Controller * @author: guoxu * @create: 2019-12-31 16:53 */ @Api(tags = "定时任务管理模块",description = "ScheduleJobController") @Slf4j @RestController @RequestMapping("sys/schedule") public class ScheduleJobController { @Autowired private IScheduleJobService scheduleJobService; @ApiOperation("添加或更新定时任务") @PostMapping("add") public String addOrUpdate(@RequestBody MgrScheduleJob mgrScheduleJob){ try { scheduleJobService.addOrUpdateScheduleJob(mgrScheduleJob); return "定时任务添加或更新成功"; } catch (Exception e) { log.error("定时任务新增或更新失败==>【{}】",e.getMessage()); return "定时任务添加或更新失败"; } } @ApiOperation("删除定时任务") @PostMapping("delete") public String delete(@ApiParam(value = "",required = true) @RequestParam String id){ try { scheduleJobService.deleteScheduleJob(id); return "删除定时任务成功"; } catch (Exception e) { log.error("删除定时任务失败==>【{}】",e.getMessage()); return "删除定时任务失败"; } } @ApiOperation("启用或停用定时任务") @PostMapping("isEnable") public String isEnable(@ApiParam(value = "",required = true) @RequestParam String id){ try { scheduleJobService.isEnableScheduleJob(id); return "启用或停用定时任务成功"; } catch (Exception e) { log.error("启用或停用定时任务失败==>【{}】",e.getMessage()); return "启用或停用定时任务失败"; } } @ApiOperation("暂停或执行定时任务") @PostMapping("pauseJob") public String pauseJob(@ApiParam(value = "",required = true) @RequestParam String id){ try { scheduleJobService.pauseScheduleJob(id); return "暂停或执行定时任务成功"; } catch (Exception e) { log.error("暂停或执行定时任务失败==>【{}】",e.getMessage()); return "暂停或执行定时任务失败"; } } }
七. 创建定时任务执行类
自定义定时任务执行类须继承QuartzJobBean:
package com.example.demo.quartztask.job;
import com.example.demo.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; /** * @program: demo * @description: 测试定时任务类 * @author: guoxu * @create: 2019-12-31 10:13 * * QuartzJobBean implements Job */ @Slf4j public class TestSchedulerJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info("执行测试定时任务==>【{}】", DateUtil.getTodayTimeString()); } }
新增定时任务SQL示例:
-- ----------------------------
-- Records of t_schedule_job
-- ----------------------------
INSERT INTO `t_schedule_job` VALUES ('rl857upqqsgdio86kpdnmuf95b', '测试任务', 'test', 'com.example.demo.quartztask.job.TestSchedulerJob', '测试创建的定时任务', '0/5 * * * * ?', 0, 1, '2019-12-31 18:50:26.674000', '2019-12-31 18:50:26.674000', 'admin');
来源:站长平台