一. 引入依赖
<!-- 引入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');
来源:站长平台