在实际项目开发中,我们想在规定时间执行一些任务,所以会经常用到定时任务。当然定时任务有很多种,本文我来介绍下我在项目中用到的quartz定时任务,项目架构采用的是微服务,主要写Spring Boot集成Quartz详解。
MySql、Mybatis、PageHelper、Spring Boot、Quartz
org.quartz-scheduler
quartz
2.2.1
org.quartz-scheduler
quartz-jobs
2.2.1
# 固定前缀org.quartz
# 定时任务开关,true-开 false-关
quartz.autoStartup=false
quartz.delaySeconds=10
org.quartz.scheduler.instanceName=DefaultQuartzScheduler
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.rmi.export=false
org.quartz.scheduler.rmi.proxy=false
org.quartz.scheduler.wrapJobExecutionInUserTransaction=false
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
# 并发个数
org.quartz.threadPool.threadCount=10
# 优先级
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
org.quartz.jobStore.misfireThreshold=5000
# 默认存储在内存中
#org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.dataSource=qzDS
org.quartz.dataSource.qzDS.maxConnections=10
package com.fintech.modules.base.quartz;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdScheduler;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;
/**
* @author lc
* @date: 2017/12/4 15:03
* @description: quartz配置加载类
*/
@Configuration
public class QuartzConfig {
private Logger logger = LoggerFactory.getLogger(getClass());
@Value("${quartz.autoStartup}")
private Boolean autoStartup;
@Value("${quartz.delaySeconds}")
private Integer delaySeconds;
@Value("${org.quartz.scheduler.instanceName}")
private String schedulerInstanceName;
@Value("${org.quartz.scheduler.rmi.export}")
private String schedulerRmiExport;
@Value("${org.quartz.scheduler.rmi.proxy}")
private String schedulerRmiProxy;
@Value("${org.quartz.scheduler.wrapJobExecutionInUserTransaction}")
private String schedulerWrapJobExecutionInUserTransaction;
@Value("${org.quartz.threadPool.class}")
private String threadPoolClass;
@Value("${org.quartz.threadPool.threadCount}")
private String threadPoolThreadCount;
@Value("${org.quartz.threadPool.threadPriority}")
private String threadPoolThreadPriority;
@Value("${org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread}")
private String threadPoolThreadsInheritContextClassLoaderOfInitializingThread;
@Value("${org.quartz.jobStore.misfireThreshold}")
private String jobStoreMisfireThreshold;
@Value("${org.quartz.jobStore.driverDelegateClass}")
private String jobStoreDriverDelegateClass;
@Value("${org.quartz.jobStore.class}")
private String jobStoreClass;
@Value("${org.quartz.jobStore.tablePrefix}")
private String jobStoreTablePrefix;
@Value("${org.quartz.jobStore.dataSource}")
private String jobStoreDataSource;
/*@Value("${org.quartz.dataSource.qzDS.maxConnections}")
private String dataSourceMaxConnections;
@Value("${spring.datasource.driver-class-name}")
private String dataSourceDriver;
@Value("${spring.datasource.url}")
private String dataSourceURL;
@Value("${spring.datasource.username}")
private String dataSourceUser;
@Value("${spring.datasource.password}")
private String dataSourcePassword;*/
@Bean
public Properties quartzProperties() throws IOException {
Properties quartzProperties = new Properties();
quartzProperties.setProperty("org.quartz.scheduler.instanceName", schedulerInstanceName);
quartzProperties.setProperty("org.quartz.scheduler.rmi.export", schedulerRmiExport);
quartzProperties.setProperty("org.quartz.scheduler.rmi.proxy", schedulerRmiProxy);
quartzProperties.setProperty("org.quartz.scheduler.wrapJobExecutionInUserTransaction", schedulerWrapJobExecutionInUserTransaction);
quartzProperties.setProperty("org.quartz.threadPool.class", threadPoolClass);
quartzProperties.setProperty("org.quartz.threadPool.threadCount", threadPoolThreadCount);
quartzProperties.setProperty("org.quartz.threadPool.threadPriority", threadPoolThreadPriority);
quartzProperties.setProperty("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", threadPoolThreadsInheritContextClassLoaderOfInitializingThread);
quartzProperties.setProperty("org.quartz.jobStore.misfireThreshold", jobStoreMisfireThreshold);
quartzProperties.setProperty("org.quartz.jobStore.class", jobStoreClass);
quartzProperties.setProperty("org.quartz.jobStore.driverDelegateClass", jobStoreDriverDelegateClass);
quartzProperties.setProperty("org.quartz.jobStore.tablePrefix", jobStoreTablePrefix);
quartzProperties.setProperty("org.quartz.jobStore.dataSource", jobStoreDataSource);
/*quartzProperties.setProperty("org.quartz.dataSource.qzDS.maxConnections", dataSourceMaxConnections);
quartzProperties.setProperty("org.quartz.dataSource.qzDS.driver", dataSourceDriver);
quartzProperties.setProperty("org.quartz.dataSource.qzDS.URL", dataSourceURL);
quartzProperties.setProperty("org.quartz.dataSource.qzDS.user", dataSourceUser);
quartzProperties.setProperty("org.quartz.dataSource.qzDS.password", dataSourcePassword);*/
return quartzProperties;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) throws IOException {
logger.info("开始配置quartz定时任务");
SchedulerFactoryBean factory = new SchedulerFactoryBean();
// 加载quartz数据源配置
factory.setQuartzProperties(quartzProperties());
// 加载数据源
factory.setDataSource(dataSource);
// 将spring上下文放入quartz中, 用于在job执行时获取注入bean
factory.setApplicationContextSchedulerContextKey("applicationContextKey");
factory.setOverwriteExistingJobs(true);
if(autoStartup) {
// 延时启动
if(delaySeconds > 0) {
factory.setStartupDelay(delaySeconds);
}
logger.info("quartz开启自动启动定时任务, 延时{}s启动", delaySeconds);
} else {
factory.setAutoStartup(false);
logger.warn("quartz未开启自动启动定时任务");
}
logger.info("quartz定时任务配置成功");
return factory;
}
}
package com.fintech.modules.quartzjobmanage.dto;
/**
* @Description: 定时任务bean
* @author lc
* @date 2018年5月29日
*/
public class JobAndTriggerDTO {
/**
* 任务名称
*/
private String jobName;
/**
* 任务所在组
*/
private String jobGroup;
/**
* 任务类名
*/
private String jobClassName;
/**
* 触发器名称
*/
private String triggerName;
/**
* 触发器所在组
*/
private String triggerGroup;
/**
* 表达式
*/
private String cronExpression;
/**
* 时区
*/
private String timeZoneId;
/**
* 状态
*/
private String triggerStart;
/**
* 创建时间
*/
private String startTime;
/**
* 上次执行时间
*/
private String prevFireTime;
/**
* 下次执行时间
*/
private String nextFireTime;
public String getTriggerStart() {
return triggerStart;
}
public void setTriggerStart(String triggerStart) {
this.triggerStart = triggerStart;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getPrevFireTime() {
return prevFireTime;
}
public void setPrevFireTime(String prevFireTime) {
this.prevFireTime = prevFireTime;
}
public String getNextFireTime() {
return nextFireTime;
}
public void setNextFireTime(String nextFireTime) {
this.nextFireTime = nextFireTime;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getJobClassName() {
return jobClassName;
}
public void setJobClassName(String jobClassName) {
this.jobClassName = jobClassName;
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName;
}
public String getTriggerGroup() {
return triggerGroup;
}
public void setTriggerGroup(String triggerGroup) {
this.triggerGroup = triggerGroup;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public String getTimeZoneId() {
return timeZoneId;
}
public void setTimeZoneId(String timeZoneId) {
this.timeZoneId = timeZoneId;
}
}
package com.fintech.modules.quartzjobmanage.dao;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.fintech.modules.quartzjobmanage.dto.JobAndTriggerDTO;
/**
* @Description: 定时任务dao
* @author lc
* @date 2018年5月29日
*/
@Mapper
public interface JobAndTriggerMapper {
/**
* @Description: 查询定时任务信息
* @author lc
*/
public List getJobAndTriggerDetails();
}
package com.fintech.modules.quartzjobmanage.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fintech.modules.quartzjobmanage.dao.JobAndTriggerMapper;
import com.fintech.modules.quartzjobmanage.dto.JobAndTriggerDTO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
/**
* @Description: 定时任务service
* @author lc
* @date 2018年5月29日
*/
@Service
public class JobAndTriggerService{
@Autowired
private JobAndTriggerMapper jobAndTriggerMapper;
/**
* @Description: 查询定时任务信息
* @author lc
*/
public PageInfo getJobAndTriggerDetails(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List list = jobAndTriggerMapper.getJobAndTriggerDetails();
PageInfo page = new PageInfo(list);
return page;
}
}
package com.fintech.modules.quartzjobmanage.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fintech.modules.base.util.SmsException;
import com.fintech.modules.quartzjobmanage.dto.JobAndTriggerDTO;
import com.fintech.modules.quartzjobmanage.service.JobAndTriggerService;
import com.fintech.modules.sms.common.dto.LayuiResult;
import com.github.pagehelper.PageInfo;
/**
* @author xujunqi
* @date: 2017/12/9 15:24
* @description: 定时任务配置控制类
*/
@RestController
@RequestMapping(value = "/quartzjob")
@Api(tags="定时任务配置控制类")
public class QuartzJobController {
private static Logger logger = LoggerFactory.getLogger(QuartzJobController.class);
@Autowired
private Scheduler scheduler;
@Autowired
private JobAndTriggerService jobAndTriggerService;
@ApiOperation(value= "添加定时任务", notes= "添加定时任务")
@PostMapping(value = "/addjob")
public String addjobController(@RequestParam(value = "jobClassName") String jobClassName,
@RequestParam(value = "jobGroupName") String jobGroupName,
@RequestParam(value = "cronExpression") String cronExpression) throws Exception {
addJob(jobClassName, jobGroupName, cronExpression);
return "定时任务添加成功";
}
public void addJob(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
if(StringUtils.isBlank(jobGroupName)) {
jobGroupName = Scheduler.DEFAULT_GROUP;
}
// 启动调度器
scheduler.start();
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName, jobGroupName).build();
//表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
.withSchedule(scheduleBuilder).build();
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
logger.error("创建定时任务失败", e);
throw new SmsException("创建定时任务失败");
}
}
/* @ApiOperation(value= "根据条件查询定时任务", notes= "根据条件查询定时任务")
@PostMapping(value = "/queryjob")
public String queryjob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
jobPause(jobClassName, jobGroupName);
return "定时任务暂停成功";
}*/
@ApiOperation(value= "根据条件暂停定时任务", notes= "根据条件暂停定时任务")
@PostMapping(value = "/pausejob")
public String pausejob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
jobPause(jobClassName, jobGroupName);
return "定时任务暂停成功";
}
public void jobPause(String jobClassName, String jobGroupName) throws Exception {
if(StringUtils.isBlank(jobGroupName)) {
jobGroupName = Scheduler.DEFAULT_GROUP;
}
// 通过SchedulerFactory获取一个调度器实例
scheduler.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@ApiOperation(value= "根据条件恢复定时任务", notes= "根据条件恢复定时任务")
@PostMapping(value = "/resumejob")
public String resumejob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
jobresume(jobClassName, jobGroupName);
return "定时任务恢复成功";
}
public void jobresume(String jobClassName, String jobGroupName) throws Exception {
if(StringUtils.isBlank(jobGroupName)) {
jobGroupName = Scheduler.DEFAULT_GROUP;
}
// 通过SchedulerFactory获取一个调度器实例
scheduler.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@ApiOperation(value= "根据条件定时任务", notes= "根据条件定时任务")
@PostMapping(value = "/reschedulejob")
public String rescheduleJob(@RequestParam(value = "jobClassName") String jobClassName,
@RequestParam(value = "jobGroupName") String jobGroupName,
@RequestParam(value = "cronExpression") String cronExpression) throws Exception {
jobreschedule(jobClassName, jobGroupName, cronExpression);
return "定时任务重新调度成功";
}
public void jobreschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
if(StringUtils.isBlank(jobGroupName)) {
jobGroupName = Scheduler.DEFAULT_GROUP;
}
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
logger.error("更新定时任务失败", e);
throw new SmsException("更新定时任务失败");
}
}
@ApiOperation(value= "根据条件删除定时任务", notes= "根据条件删除定时任务")
@PostMapping(value = "/deletejob")
public String deletejob(@RequestParam(value = "jobClassName") String jobClassName, @RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
jobdelete(jobClassName, jobGroupName);
return "定时任务删除成功";
}
public void jobdelete(String jobClassName, String jobGroupName) throws Exception {
if(StringUtils.isBlank(jobGroupName)) {
jobGroupName = Scheduler.DEFAULT_GROUP;
}
// 通过SchedulerFactory获取一个调度器实例
scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));//停止触发器
scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));//移除触发器
scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));//删除任务
}
/**
* @Description: 定时任务管理
* @author lc
*/
@ApiOperation(value= "定时任务管理", notes= "根据条件管理定时任务")
@GetMapping(value = "/queryjob")
public Map queryjob(@RequestParam(value = "pageNum") Integer pageNum, @RequestParam(value = "pageSize") Integer pageSize) {
PageInfo jobAndTrigger = jobAndTriggerService.getJobAndTriggerDetails(pageNum, pageSize);
Map map = new HashMap();
map.put("JobAndTrigger", jobAndTrigger);
map.put("number", jobAndTrigger.getTotal());
return map;
}
/**
* @Description: 查询定时任务
* @author lc
*/
@ApiOperation(value= "查询定时任务", notes= "根据条件查询定时任务")
@GetMapping(value = "/queryJobList")
public LayuiResult queryJobList(@RequestParam Map paramMap) {
PageInfo list = jobAndTriggerService.getJobAndTriggerDetails(Integer.parseInt(paramMap.get("page").toString()), Integer.parseInt(paramMap.get("limit").toString()));
return LayuiResult.data(list.getTotal(), list.getList());
}
public static QuartzJobBean getClass(String classname) throws Exception {
Class> class1 = Class.forName(classname);
return (QuartzJobBean) class1.newInstance();
}
}
package com.fintech.modules.base.quartzjobs;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import com.fintech.modules.sms.smsreport.service.SmsLogStatusReportService;
/**
* @Description: 每分钟/短信报文统计发送状态
* @author lc
* @date 2018年4月10日
* 每2分钟统计一次
*/
@Component
public class SmsReportStatisJob extends QuartzJobBean {
private static final long serialVersionUID = 1L;
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.info("开始执行-定时短信发送报文统计:{}");
try {
SchedulerContext cont = context.getScheduler().getContext();
ApplicationContext appCtx = (ApplicationContext) cont.get("applicationContextKey");
// 调用具体sercive业务代码
SmsLogStatusReportService service = appCtx.getBean(SmsLogStatusReportService.class);
service.smsReportStatis();
} catch (Exception e) {
logger.error("每分钟/短信报文跑批统计发送状态异常!{}", e);
}
logger.info("执行结束-定时短信发送报文统计:{}");
}
}
在Spring Boot的工程中,静态页面可以放在资源文件static目录下,controller已经写好了,页面完全按照自己的需求去实现即可,下面是我拷贝别人的管理页面,这里贴一下代码
定时任务
查询
添加
暂停 恢复 删除 修改