目录
功能说明
添加依赖
创建定时任务实体
工具类
service接口
定时任务的实现
具体操作
运行环境jdk1.8+springboot+maven
功能说明
动态的进行定时任务的添加,暂停、修改等。任务信息存储在数据库,所以会涉及到数据库方面的知识
添加依赖
在pom.xml文件中添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
创建定时任务实体
我这里使用的是 mybatis-plus ,如果是使用其他的orm框架,理解思路后就好了。
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
@TableName("sys_scheduled")
public class Scheduled implements Serializable {
private static final long serialVersionUID = 8324997582188610887L;
@TableId(type = IdType.UUID)
private String id;
private String className;
/**
* 任务key
*/
private String jobKey;
/**
* 人物的cron表达式
*/
private String cronExpression;
private String remark;
/**
* 任务状态
*/
private String status;
private Date createTime;
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getJobKey() {
return jobKey;
}
public void setJobKey(String jobKey) {
this.jobKey = jobKey;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
mapper文件
接口
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.myapp.base.sys.job.entity.Scheduled;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;
import java.util.List;
@Mapper
@Component
public interface ScheduledMapper extends BaseMapper<Scheduled> {
List<Scheduled> selectCanRun();
}
XML
<?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.myapp.base.sys.job.mapper.ScheduledMapper">
<resultMap id="scheduled" type="com.myapp.base.sys.job.entity.Scheduled">
<id column="ID" property="id"></id>
<result column="CLASS_NAME" property="className"></result>
<result column="STATUS" property="status"></result>
<result column="REMARK" property="remark"></result>
<result column="CRON_EXPRESSION" property="cronExpression"></result>
<result column="JOB_KEY" property="jobKey"></result>
<result column="CREATE_TIME" property="createTime"></result>
</resultMap>
<select id="selectCanRun" resultMap="scheduled">
select * from sys_scheduled where STATUS='1'
</select>
</mapper>
工具类
主要实现就是在这两个类里面,数据库相关的操作都是增删查改。
QuartzUtils?
import com.myapp.base.sys.job.entity.Scheduled;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class QuartzUtils {
@Autowired
private static Scheduler scheduler;
@Autowired
ApplicationContext applicationContext;
@PostConstruct
public void init() {
QuartzUtils.scheduler = applicationContext.getBean(Scheduler.class);
}
public static void createScheduleJob(Scheduled scheduled) throws Exception{
//获取到定时任务的执行类 必须是类的绝对路径名称
//定时任务类需要是job类的具体实现 QuartzJobBean是job的抽象类。
Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(scheduled.getClassName());
// 构建定时任务信息
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(scheduled.getJobKey()).build();
// 设置定时任务执行方式
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduled.getCronExpression());
// 构建触发器trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(scheduled.getJobKey()).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 根据任务名称暂停定时任务
* @param jobName 定时任务名称
* @throws SchedulerException
*/
public static void pauseScheduleJob(String jobName){
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
System.out.println("暂停定时任务出错:"+e.getMessage());
}
}
/**
* 根据任务名称恢复定时任务
* @param jobName 定时任务名称
* @throws SchedulerException
*/
public static void resumeScheduleJob(String jobName) {
JobKey jobKey = JobKey.jobKey(jobName);
try {
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
System.out.println("启动定时任务出错:"+e.getMessage());
}
}
/**
* 根据任务名称立即运行一次定时任务
* @param jobName 定时任务名称
* @throws SchedulerException
*/
public static void runOnce(String jobName) throws Exception{
JobKey jobKey = JobKey.jobKey(jobName);
scheduler.triggerJob(jobKey);
}
/**
* 更新定时任务
* @param scheduled 定时任务信息类
* @throws SchedulerException
*/
public static void updateScheduleJob(Scheduled scheduled) throws Exception{
//获取到对应任务的触发器
TriggerKey triggerKey = TriggerKey.triggerKey(scheduled.getJobKey());
//设置定时任务执行方式
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduled.getCronExpression());
//重新构建任务的触发器trigger
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//重置对应的job
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* 根据定时任务名称从调度器当中删除定时任务
* @param jobName 定时任务名称
* @throws SchedulerException
*/
public static void deleteScheduleJob(String jobName) throws Exception{
TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
JobKey jobKey = JobKey.jobKey(jobName);
scheduler.pauseTrigger(triggerKey);
scheduler.unscheduleJob(triggerKey);
scheduler.deleteJob(jobKey);
}
}
ScheduledUtils?
import com.myapp.base.sys.job.entity.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
/**
* 定时任务
*/
@Component
public class ScheduledUtils {
private ReentrantLock lock = new ReentrantLock();
private Map<String,Object> scheduledMap = Collections.synchronizedMap(new Hashtable<String,Object>());
/**
* 添加定时任务
* @param scheduled
* @return
*/
public boolean addSchedulerJob(Scheduled scheduled){
lock.lock();
boolean flag =true;
try{
if(scheduledMap.containsKey(scheduled.getJobKey())){
System.out.println("任务已添加");
return flag;
}
QuartzUtils.createScheduleJob(scheduled);
scheduledMap.put(scheduled.getJobKey(),"1");
}catch (Exception e){
System.out.println(e);
flag = false;
} finally {
lock.unlock();
}
return flag;
}
/**
* 更新定时任务
* @param scheduled
* @return
*/
public boolean updateSchedulerJob(Scheduled scheduled){
boolean flag =true;
try{
if(!scheduledMap.containsKey(scheduled.getJobKey())){
addSchedulerJob(scheduled);
}else{
QuartzUtils.updateScheduleJob(scheduled);
}
}catch (Exception e){
flag = false;
}
return flag;
}
public boolean deleteSchedulerJob(Scheduled scheduled){
boolean flag =true;
try{
if(scheduledMap.containsKey(scheduled.getJobKey())){
QuartzUtils.deleteScheduleJob(scheduled.getJobKey());
scheduledMap.remove(scheduled.getJobKey());
}
}catch (Exception e){
flag = false;
}
return flag;
}
public boolean runOnceSchedulerJob(Scheduled scheduled){
boolean flag =true;
try{
if(scheduledMap.containsKey(scheduled.getJobKey())){
QuartzUtils.runOnce(scheduled.getJobKey());
}
}catch (Exception e){
flag = false;
}
return flag;
}
}
service接口
import com.myapp.base.sys.job.entity.Scheduled;
import java.util.List;
public interface IScheduledService {
boolean updateScheduled(Scheduled scheduled);
boolean updateScheduledStartOrStop(Scheduled scheduled);
boolean addScheduled(Scheduled scheduled);
List<Scheduled> selectAllScheduled();
boolean runOnce(Scheduled scheduled);
}
对应的实现类
这里实现类中实现了ApplicationRunner 中的run方法,作用在于,项目启动后,查询数据库中启用的定时工作,并逐一启用。
代码里 SysHelper.YES? 等价与 “1” 表示的是任务的状态,启用与禁用。
import com.myapp.base.config.jobconfig.ScheduledUtils;
import com.myapp.base.sys.SysHelper;
import com.myapp.base.sys.job.entity.Scheduled;
import com.myapp.base.sys.job.mapper.ScheduledMapper;
import com.myapp.base.sys.job.service.IScheduledService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Transactional
@Service
public class ScheduledService implements IScheduledService, ApplicationRunner {
@Autowired
ScheduledUtils scheduler;
@Autowired
ScheduledMapper scheduledMapper;
/**
* 查询数据库中可执行的
* @param args
* @throws Exception
*/
@Override
public void run(ApplicationArguments args) throws Exception {
List<Scheduled> scheduleds = scheduledMapper.selectCanRun();
if(scheduleds != null && scheduleds.size()>0){
for(Scheduled item:scheduleds){
scheduler.addSchedulerJob(item);
}
}
}
@Override
public boolean updateScheduled(Scheduled scheduled) {
int i = scheduledMapper.updateById(scheduled);
if(i>0 && SysHelper.YES.equals(scheduled.getStatus())){
return scheduler.updateSchedulerJob(scheduled);
}else if(i>0){
return scheduler.deleteSchedulerJob(scheduled);
}
return true;
}
@Override
public boolean updateScheduledStartOrStop(Scheduled scheduled) {
int i = scheduledMapper.updateById(scheduled);
if(i>0){
if(SysHelper.YES.equals(scheduled.getStatus())){
return scheduler.addSchedulerJob(scheduled);
}else{
return scheduler.deleteSchedulerJob(scheduled);
}
}
return false;
}
@Override
public boolean addScheduled(Scheduled scheduled) {
scheduled.setCreateTime(new Date());
if(scheduledMapper.insert(scheduled)>0){
return scheduler.addSchedulerJob(scheduled);
}
return false;
}
@Override
public List<Scheduled> selectAllScheduled() {
return scheduledMapper.selectList(null);
}
@Override
public boolean runOnce(Scheduled scheduled) {
return scheduler.runOnceSchedulerJob(scheduled);
}
}
定时任务的实现
创建类并继承QuartzJobBean类,实现其中的executeInternal方法。
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class testJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println("这里写你的定时任务");
}
}
具体操作
前端页面,用vue简单搭了个界面,丑陋了点。
将我们创建的定时任务添加上去。
?注意:
1.类名一定要正确,因为我们是通过类名反射后获取对应的运行时类的,若类名不正确,就无法获取到类。
2.关键字不能与之前重复,因为我们是用map集合进行记录当前已运行的任务,关键字作为map的key若是重复了会导致该任务不会启动(启动时是先判断map中是否有该任务的,不想这样的,可自己改一下添加定时任务的逻辑)
具体controller和前端页面就不多说了,就是简单的传数据。
ScheduledUtils类
addSchedulerJob? 添加任务
updateSchedulerJob 更新定时任务,主要是更新执行周期
deleteSchedulerJob 设置禁用时调用
runOnceSchedulerJob 需要立即执行时调用
水平有限,仅供参考。
|