Spring+Mybatis +Quartz 实现定时任务管理
任务要求:通过开源任务调度框架Quartz,实现定时任务的添加、修改、删除、暂停、恢复和分页查询功能。
第一步:base 模块添加quartz jar包依赖:
<!-- 定时任务框架 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
第二步:新增Quartz配置类对象:SchedulerConfig.java
import java.io.IOException;
import java.util.Properties;
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import com.***.ucas.job.factory.CustomerJobFactory;
@Configuration
public class SchedulerConfig {
@Autowired
private CustomerJobFactory jobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setOverwriteExistingJobs(true);
// 延时启动
factory.setStartupDelay(20);
// 加载quartz数据源配置
factory.setQuartzProperties(quartzProperties());
// 自定义Job Factory,用于Spring注入
factory.setJobFactory(jobFactory);
return factory;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
// 在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
/*
* quartz初始化监听器
*/
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
/*
* 通过SchedulerFactoryBean获取Scheduler的实例
*/
@Bean(name = "scheduler")
public Scheduler scheduler() throws Exception {
return schedulerFactoryBean().getScheduler();
}
}
自定义定时任务工厂:CustomerJobFactory.java
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;
@Component
public class CustomerJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
三、添加Quartz的配置文件:在service模块的src/main/resource文件夹下新建quartz.properties 配置文件,配置文件的内容如下:
# 固定前缀org.quartz
# 主要分为scheduler、threadPool、jobStore、plugin等部分
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 5
# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 5000
#MySQL 持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
# 表名前缀
org.quartz.jobStore.tablePrefix = qrtz_
# 指定数据库
org.quartz.jobStore.dataSource = ucas
# 指定mysql 驱动
org.quartz.dataSource.ucas.driver = com.mysql.cj.jdbc.Driver
# 数据库连接地址
org.quartz.dataSource.ucas.URL = jdbc:mysql://192.168.*.**:3306/ucas?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
# 数据库账户
org.quartz.dataSource.ucas.user = root
# 数据库密码
org.quartz.dataSource.ucas.password = ******
# 配置最大连接数
org.quartz.dataSource.ucas.maxConnections = 10
四、自定义定时任务对应的实体对象:SysCron.java
import java.util.Date;
import com.***.common.model.BaseModel;
@SuppressWarnings("serial")
public class SysCron extends BaseModel {
private String id;
private String jobName;
private String jobDescription;
private String jobGroupName;
private String jobClassName;
private String triggerName;
private String triggerGroupName;
private String prevFireTime;
private String nextFireTime;
private String cronExpression;
private String triggerState;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id == null ? null : id.trim();
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName == null ? null : jobName.trim();
}
public String getJobDescription() {
return jobDescription;
}
public void setJobDescription(String jobDescription) {
this.jobDescription = jobDescription == null ? null : jobDescription.trim();
}
public String getJobGroupName() {
return jobGroupName;
}
public void setJobGroupName(String jobGroupName) {
this.jobGroupName = jobGroupName == null ? null : jobGroupName.trim();
}
public String getJobClassName() {
return jobClassName;
}
public void setJobClassName(String jobClassName) {
this.jobClassName = jobClassName == null ? null : jobClassName.trim();
}
public String getTriggerName() {
return triggerName;
}
public void setTriggerName(String triggerName) {
this.triggerName = triggerName == null ? null : triggerName.trim();
}
public String getTriggerGroupName() {
return triggerGroupName;
}
public void setTriggerGroupName(String triggerGroupName) {
this.triggerGroupName = triggerGroupName == null ? null : triggerGroupName.trim();
}
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 getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression == null ? null : cronExpression.trim();
}
public String getTriggerState() {
return triggerState;
}
public void setTriggerState(String triggerState) {
this.triggerState = triggerState == null ? null : triggerState.trim();
}
}
自定义接口服务层:SysCronService.java
import java.util.List;
import java.util.Map;
import com.***.common.model.PageParam;
import com.***.common.page.PageData;
import com.***.ucas.domain.SysCron;
public interface SysCronService{
// 全部查询
List<SysCron> selectAll(Map<String,Object> parame);
//分页查询
PageData<SysCron> selectAllPage(Map<String,Object> parame, PageParam rb);
// 添加定时任务
public boolean addSysCron(SysCron entity);
// 更新定时任务
public boolean updateSysCron(SysCron entity);
// 删除定时任务
public boolean deleteSysCron(SysCron entity);
// 暂时定时任务
public boolean pauseSysCron(SysCron entity);
// 恢复定时任务
public boolean resumeJob(SysCron entity);
}
自定义接口服务实现层:SysCronServiceImpl .java (核心代码:实现定时任务新增、修改、暂停、恢复和删除功能)
import java.util.List;
import java.util.Map;
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.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.***.common.job.BaseJob;
import com.***.common.model.PageParam;
import com.***.common.page.PageData;
import com.***.ucas.api.SysCronService;
import com.***.ucas.domain.SysCron;
import com.***.ucas.mapper.SysCronMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
@Service
public class SysCronServiceImpl implements SysCronService {
private static final Logger log = LoggerFactory.getLogger(SysCronServiceImpl.class);
@Autowired
private Scheduler scheduler;
@Autowired
private SysCronMapper mapper;
@Override
public List<SysCron> selectAll(Map<String, Object> parame) {
return mapper.selectAll(parame);
}
@Override
public PageData<SysCron> selectAllPage(Map<String, Object> parame, PageParam rb) {
// TODO Auto-generated method stub
PageData<SysCron> pageData = new PageData<SysCron>();
PageHelper.startPage(rb.getPageNo(), rb.getLimit());
List<SysCron> rs = mapper.selectAll(parame);
PageInfo<SysCron> pageInfo = new PageInfo<SysCron>(rs);
pageData.setData(pageInfo.getList());
pageData.setPageNum(pageInfo.getPageNum());
pageData.setPageSize(pageInfo.getPageSize());
pageData.setTotalCount(pageInfo.getTotal());
return pageData;
}
@Override
public boolean addSysCron(SysCron entity) {
boolean target = false;
try {
// 启动调度器
scheduler.start();
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(entity.getJobClassName()).getClass())
.withIdentity(entity.getJobClassName(), entity.getJobGroupName()).build();
// 表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(entity.getCronExpression());
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(entity.getJobClassName(), entity.getJobGroupName()).withSchedule(scheduleBuilder)
.build();
scheduler.scheduleJob(jobDetail, trigger);
target = true;
} catch (Exception e) {
log.error("创建定时任务异常" + e.getMessage());
return target;
}
return target;
}
@Override
public boolean updateSysCron(SysCron entity) {
boolean target = false;
try {
TriggerKey triggerKey = TriggerKey.triggerKey(entity.getJobClassName(), entity.getJobGroupName());
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(entity.getCronExpression());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
target = true;
} catch (Exception e) {
log.error("定时任务更新失败" + e.getMessage());
return target;
}
return target;
}
@Override
public boolean deleteSysCron(SysCron entity) {
boolean target = false;
try {
scheduler.pauseTrigger(TriggerKey.triggerKey(entity.getJobClassName(), entity.getJobGroupName()));
scheduler.unscheduleJob(TriggerKey.triggerKey(entity.getJobClassName(), entity.getJobGroupName()));
scheduler.deleteJob(JobKey.jobKey(entity.getJobClassName(), entity.getJobGroupName()));
target = true;
} catch (Exception e) {
log.error("定时任务删除失败" + e.getMessage());
return target;
}
return target;
}
@Override
public boolean pauseSysCron(SysCron entity) {
boolean target = false;
try {
scheduler.pauseJob(JobKey.jobKey(entity.getJobClassName(), entity.getJobGroupName()));
target = true;
} catch (Exception e) {
log.error("暂停定时任务失败" + e.getMessage());
return target;
}
return target;
}
@Override
public boolean resumeJob(SysCron entity) {
boolean target = false;
try {
scheduler.resumeJob(JobKey.jobKey(entity.getJobClassName(), entity.getJobGroupName()));
target = true;
} catch (Exception e) {
log.error("恢复定时任务失败" + e.getMessage());
return target;
}
return target;
}
/**
*
* @param classname
* @return
* @throws Exception
*/
public static BaseJob getClass(String classname) throws Exception {
Class<?> class1 = Class.forName(classname);
return (BaseJob) class1.newInstance();
}
}
数据库mapp 接口定义和mapp 查询映射
import java.util.List;
import java.util.Map;
import com.***.common.model.PageParam;
import com.***.common.page.PageData;
import com.***.ucas.domain.SysCron;
public interface SysCronMapper {
// 全部查询
List<SysCron> selectAll(Map<String,Object> parame);
//分页查询
PageData<SysCron> selectAllPage(Map<String,Object> parame, PageParam rb);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.digipower.ucas.mapper.SysCronMapper">
<!-- 公共查询条件 -->
<sql id="condition">
<if test="jobClassName != null">
and jd.job_class_name = #{jobClassName,jdbcType=VARCHAR}
</if>
<if test="jobGroupName != null">
and jd.job_group = #{jobGroupName,jdbcType=VARCHAR}
</if>
<if test="triggerName != null">
and t.trigger_name = #{triggerName,jdbcType=VARCHAR}
</if>
<if test="triggerGroupName != null">
and t.trigger_group = #{triggerGroupName,jdbcType=VARCHAR}
</if>
<if test="triggerState != null">
and t.trigger_state = #{triggerState, jdbcType=VARCHAR}
</if>
</sql>
<!-- 全部查询 -->
<select id="selectAll" resultType="com.digipower.ucas.domain.SysCron">
select
jd.job_name as jobname,
jd.description as jobdescription,
jd.job_group as jobgroupname,
jd.job_class_name as jobclassname,
t.trigger_name as triggername,
t.trigger_group as triggergroupname,
from_unixtime(t.prev_fire_time/1000,'%y-%m-%d %t') as prevfiretime,
from_unixtime(t.next_fire_time/1000,'%y-%m-%d %t') as nextfiretime,
ct.cron_expression as cronexpression,
t.trigger_state as triggerstate
from
qrtz_job_details jd
join qrtz_triggers t
join qrtz_cron_triggers ct on jd.job_name = t.job_name
and t.trigger_name = ct.trigger_name
and t.trigger_group = ct.trigger_group
where 1 = 1
<include refid="condition" />
</select>
</mapper>
至此,Spring + Mybatis + Quartz 实现定义任务管理的基本功能封装完毕。
效果截图:待补充
第五步:添加自定义定时任务:
定义通用公共基础任务:BaseJob.java
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* 定时任务基础类
* @author zzg
*
*/
public interface BaseJob extends Job {
public void execute(JobExecutionContext context) throws JobExecutionException;
}
添加自定义Job
import java.util.Date;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.***.common.job.BaseJob;
public class SimpleJob implements BaseJob {
private static final Logger log = LoggerFactory.getLogger(SimpleJob.class);
public SimpleJob(){
System.out.println(new Date() + "SimpleJob");
try {
Thread.sleep(10000);
System.out.println("任务 SimpleJob 开始干活。。。");
} catch (InterruptedException e) {
e.printStackTrace();
log.error("SimpleJob 定时任务报错:" + e.getMessage());
}
System.out.println(new Date() + "SimpleJob 任务结束------------------------------------");
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println("SimpleJob执行时间: " + new Date());
}
}
import java.util.List;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import com.alibaba.fastjson.JSONObject;
import com.***.common.job.BaseJob;
import com.***.ucas.domain.SysDataCategory;
import com.***.ucas.mapper.SysDataCategoryMapper;
public class SysDataCategoryJob implements BaseJob {
@Autowired
private SysDataCategoryMapper mapper;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
List<SysDataCategory> list = mapper.selectAll();
if(list != null && list.size() > 0){
String json = JSONObject.toJSONString(list);
System.out.println("json 内容:" + json);
}
}
}
补充说明:Quartz.2.x MySQL 建库脚本:请参考:https://blog.csdn.net/zhouzhiwengang/article/details/101776655
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。