需求
在不重启服务的情况下,动态添加定时任务
效果
启动项目(有一个已存在的定时任务)
添加一个定时任务
查看控制台(动态添入定时任务)
实现步骤
pom.xml引入依赖
很多无关依赖可以自己删除,主要依赖:spring-boot-starter-quartz
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-job-quickstart</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-plus-job-quickstart</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
<scope>runtime</scope>
</dependency>
<!-- Quartz定时任务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- Swagger API文档 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
yml添加线程池配置
task:
pool:
# 核心线程池大小
core-pool-size: 10
# 最大线程数
max-pool-size: 30
# 活跃时间
keep-alive-seconds: 60
# 队列容量
queue-capacity: 50
数据库文件
/*
Navicat MySQL Data Transfer
Source Server : 本地
Source Server Version : 80016
Source Host : 127.0.0.1:3306
Source Database : job
Target Server Type : MYSQL
Target Server Version : 80016
File Encoding : 65001
Date: 2020-10-21 17:52:45
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for quartz_job
-- ----------------------------
DROP TABLE IF EXISTS `quartz_job`;
CREATE TABLE `quartz_job` (
`id` varchar(36) NOT NULL,
`bean_name` varchar(32) DEFAULT NULL COMMENT 'Spring Bean名称',
`cron_expression` varchar(32) DEFAULT NULL COMMENT 'cron 表达式',
`is_pause` int(11) DEFAULT NULL COMMENT '状态:1暂停、0启用',
`job_name` varchar(32) DEFAULT NULL COMMENT '任务名称',
`method_name` varchar(32) DEFAULT NULL COMMENT '方法名称',
`params` varchar(500) DEFAULT NULL COMMENT '参数',
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
`update_time` datetime DEFAULT NULL COMMENT '创建或更新日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of quartz_job
-- ----------------------------
INSERT INTO `quartz_job` VALUES ('1318039441581010946', 'visitsTask', '0/1 * * * * ?', '0', '更新访问量', 'run', '1318039441581010946', '测试数据', '2020-10-19 13:51:07');
INSERT INTO `quartz_job` VALUES ('1318852329113763842', 'visitsTask', '0/1 * * * * ?', '0', '新增定时', 'run', '000001', '测试', null);
-- ----------------------------
-- Table structure for quartz_log
-- ----------------------------
DROP TABLE IF EXISTS `quartz_log`;
CREATE TABLE `quartz_log` (
`id` varchar(36) NOT NULL,
`baen_name` varchar(200) DEFAULT NULL COMMENT 'Bean名称',
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
`cron_expression` varchar(32) DEFAULT NULL COMMENT 'cron表达式',
`exception_detail` longtext COMMENT '异常详细',
`is_success` int(11) DEFAULT NULL COMMENT '状态 1:成功 0:失败',
`job_name` varchar(200) DEFAULT NULL COMMENT '任务名称',
`method_name` varchar(200) DEFAULT NULL COMMENT '方法名称',
`params` varchar(200) DEFAULT NULL COMMENT '参数',
`time` bigint(20) DEFAULT NULL COMMENT '耗时(毫秒)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of quartz_log
-- ----------------------------
INSERT INTO `quartz_log` VALUES ('1318832884848824321', 'visitsTask', null, '0/1 * * * * ?', '执行成功', '1', '更新访问量', 'run', '1315548171037986818,1318039441581010946', '1');
INSERT INTO `quartz_log` VALUES ('1318832888502063106', 'visitsTask', null, '0/1 * * * * ?', '执行成功', '1', '更新访问量', 'run', '1315548171037986818,1318039441581010946', '2');
INSERT INTO `quartz_log` VALUES ('1318852710766067715', 'visitsTask', null, '0/1 * * * * ?', '执行成功', '1', '新增定时', 'run', '000001', '1');
INSERT INTO `quartz_log` VALUES ('1318852714960371713', 'visitsTask', null, '0/1 * * * * ?', '执行成功', '1', '更新访问量', 'run', '1315548171037986818,1318039441581010946', '0');
INSERT INTO `quartz_log` VALUES ('1318852714960371714', 'visitsTask', null, '0/1 * * * * ?', '执行成功', '1', '新增定时', 'run', '000001', '0');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL,
`name` varchar(255) COLLATE utf8mb4_croatian_ci DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`email` varchar(255) COLLATE utf8mb4_croatian_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_croatian_ci;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'Jone', '18', 'test1@baomidou.com');
INSERT INTO `user` VALUES ('2', 'Jack', '20', 'test2@baomidou.com');
INSERT INTO `user` VALUES ('3', 'Tom', '21', 'test3@baomidou.com');
INSERT INTO `user` VALUES ('4', 'Sandy', '22', 'test4@baomidou.com');
代码块
package com.mybatisplus.job.threadPool;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 配置属性类
*/
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class AsyncTaskProperties {
private int corePoolSize;
private int maxPoolSize;
private int keepAliveSeconds;
private int queueCapacity;
}
package com.mybatisplus.job.threadPool;
import org.springframework.stereotype.Component;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 自定义线程名称
*/
@Component
public class TheadFactoryName implements ThreadFactory {
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public TheadFactoryName() {
this("el-pool");
}
private TheadFactoryName(String name){
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的
this.namePrefix = name +
POOL_NUMBER.getAndIncrement();
}
@Override
public Thread newThread(Runnable r) {
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程
Thread t = new Thread(group, r,
namePrefix + "-thread-"+threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
package com.mybatisplus.job.threadPool;
import com.mybatisplus.job.SpringContextHolder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 用于获取自定义线程池
*/
public class ThreadPoolExecutorUtil {
public static ThreadPoolExecutor getPoll(){
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class);
return new ThreadPoolExecutor(
properties.getCorePoolSize(),
properties.getMaxPoolSize(),
properties.getKeepAliveSeconds(),
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(properties.getQueueCapacity()),
new TheadFactoryName()
);
}
}
package com.mybatisplus.job;
import com.mybatisplus.entity.QuartzJob;
import com.mybatisplus.entity.QuartzLog;
import com.mybatisplus.job.threadPool.ThreadPoolExecutorUtil;
import com.mybatisplus.mapper.QuartzJobMapper;
import com.mybatisplus.mapper.QuartzLogMapper;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.QuartzJobBean;
import javax.annotation.Resource;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
@Async
public class ExecutionJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private static final String JOB_NAME = "TASK_";
@Resource(name = "scheduler")
private Scheduler scheduler;
/** 该处仅供参考 */
private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();
@Override
@SuppressWarnings("unchecked")
protected void executeInternal(JobExecutionContext context) {
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
// 获取spring bean
QuartzJobMapper quartzJobMapper = SpringContextHolder.getBean(QuartzJobMapper.class);
QuartzLogMapper quartzLogMapper = SpringContextHolder.getBean(QuartzLogMapper.class);
QuartzLog log = new QuartzLog();
log.setJobName(quartzJob.getJobName());
log.setBaenName(quartzJob.getBeanName());
log.setMethodName("run");
log.setParams(quartzJob.getParams());
long startTime = System.currentTimeMillis();
log.setCronExpression(quartzJob.getCronExpression());
try {
// 执行任务
logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),quartzJob.getParams());
Future<?> future = EXECUTOR.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
log.setTime(times);
// 任务状态
log.setIsSuccess(1);
log.setExceptionDetail("执行成功");
logger.info("任务执行完毕,任务名称:{} 总共耗时:{} 毫秒", quartzJob.getJobName(), times);
} catch (Exception e) {
logger.info("任务执行失败,失败原因{}",e.getMessage());
long times = System.currentTimeMillis() - startTime;
log.setTime(times);
// 任务状态 1:成功 0:失败
log.setIsSuccess(0);
log.setExceptionDetail("定时执行失败");
quartzJob.setIsPause(1);
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
} catch (Exception ee){
logger.info("定时任务暂停失败{}",ee.getMessage());
throw new BadRequestException("定时任务暂停失败");
}
//更新状态
quartzJobMapper.updateById(quartzJob);
} finally {
quartzLogMapper.insert(log);
}
}
}
package com.mybatisplus.job;
import com.mybatisplus.entity.QuartzJob;
import com.mybatisplus.entity.QuartzLog;
import com.mybatisplus.job.threadPool.ThreadPoolExecutorUtil;
import com.mybatisplus.mapper.QuartzJobMapper;
import com.mybatisplus.mapper.QuartzLogMapper;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.QuartzJobBean;
import javax.annotation.Resource;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
@Async
public class ExecutionJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass());
private static final String JOB_NAME = "TASK_";
@Resource(name = "scheduler")
private Scheduler scheduler;
/** 该处仅供参考 */
private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();
@Override
@SuppressWarnings("unchecked")
protected void executeInternal(JobExecutionContext context) {
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
// 获取spring bean
QuartzJobMapper quartzJobMapper = SpringContextHolder.getBean(QuartzJobMapper.class);
QuartzLogMapper quartzLogMapper = SpringContextHolder.getBean(QuartzLogMapper.class);
QuartzLog log = new QuartzLog();
log.setJobName(quartzJob.getJobName());
log.setBaenName(quartzJob.getBeanName());
log.setMethodName("run");
log.setParams(quartzJob.getParams());
long startTime = System.currentTimeMillis();
log.setCronExpression(quartzJob.getCronExpression());
try {
// 执行任务
logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),quartzJob.getParams());
Future<?> future = EXECUTOR.submit(task);
future.get();
long times = System.currentTimeMillis() - startTime;
log.setTime(times);
// 任务状态
log.setIsSuccess(1);
log.setExceptionDetail("执行成功");
logger.info("任务执行完毕,任务名称:{} 总共耗时:{} 毫秒", quartzJob.getJobName(), times);
} catch (Exception e) {
logger.info("任务执行失败,失败原因{}",e.getMessage());
long times = System.currentTimeMillis() - startTime;
log.setTime(times);
// 任务状态 1:成功 0:失败
log.setIsSuccess(0);
log.setExceptionDetail("定时执行失败");
quartzJob.setIsPause(1);
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
} catch (Exception ee){
logger.info("定时任务暂停失败{}",ee.getMessage());
throw new BadRequestException("定时任务暂停失败");
}
//更新状态
quartzJobMapper.updateById(quartzJob);
} finally {
quartzLogMapper.insert(log);
}
}
}
package com.mybatisplus.job;
import com.mybatisplus.entity.QuartzJob;
import com.mybatisplus.mapper.QuartzJobMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class JobRunner implements ApplicationRunner {
@Autowired
private QuartzJobMapper quartzJobMapper;
@Autowired
private QuartzManage quartzManage;
/**
* 项目启动时重新激活启用的定时任务
* @param applicationArguments /
*/
@Override
public void run(ApplicationArguments applicationArguments){
printSingleColor("",31,1,"--------------------注入定时任务---------------------");
printSingleColor("",1,1,"");
List<QuartzJob> quartzJobs = quartzJobMapper.getList();
quartzJobs.stream().forEach(x ->{
printSingleColor("",32,1,"注入--------------------->" + x.getJobName());
printSingleColor("",1,1,"");
});
quartzJobs.forEach(quartzManage::addJob);
printSingleColor("",34,1,"--------------------定时任务注入完成---------------------");
printSingleColor("",1,1,"");
}
/**
*
* @param pattern 前面的图案 such as "=============="
* @param code 颜色代号:背景颜色代号(41-46);前景色代号(31-36)
* @param n 数字+m:1加粗;3斜体;4下划线
* @param content 要打印的内容
*/
public static void printSingleColor(String pattern,int code,int n,String content){
System.out.format("%s\33[%d;%dm%s%n", pattern, code, n, content);
}
}
package com.mybatisplus.job;
import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
/**
* 定时任务配置
* @author /
*/
@Configuration
public class QuartzConfig {
/**
* 解决Job中注入Spring Bean为null的问题
*/
@Component("quartzJobFactory")
public static class QuartzJobFactory extends AdaptableJobFactory {
private final AutowireCapableBeanFactory capableBeanFactory;
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
/**
* 注入scheduler到spring
* @param quartzJobFactory /
* @return Scheduler
* @throws Exception /
*/
@Bean(name = "scheduler")
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
factoryBean.setJobFactory(quartzJobFactory);
factoryBean.afterPropertiesSet();
Scheduler scheduler=factoryBean.getScheduler();
scheduler.start();
return scheduler;
}
}
package com.mybatisplus.job;
import com.mybatisplus.entity.QuartzJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
import static org.quartz.TriggerBuilder.newTrigger;
@Slf4j
@Component
public class QuartzManage {
private static final String JOB_NAME = "TASK_";
@Resource(name = "scheduler")
private Scheduler scheduler;
public void addJob(QuartzJob quartzJob){
try {
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).
withIdentity(JOB_NAME + quartzJob.getId()).build();
//通过触发器名和cron 表达式创建 Trigger
Trigger cronTrigger = newTrigger()
.withIdentity(JOB_NAME + quartzJob.getId())
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
.build();
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
//重置启动时间
((CronTriggerImpl)cronTrigger).setStartTime(new Date());
//执行定时任务
scheduler.scheduleJob(jobDetail,cronTrigger);
// 暂停任务
if (quartzJob.getIsPause().equals(1)) {
pauseJob(quartzJob);
}
} catch (Exception e){
log.error("创建定时任务失败", e);
throw new BadRequestException("创建定时任务失败");
}
}
/**
* 更新job cron表达式
* @param quartzJob /
*/
public void updateJobCron(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null){
addJob(quartzJob);
trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
}
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//重置启动时间
((CronTriggerImpl)trigger).setStartTime(new Date());
trigger.getJobDataMap().put(QuartzJob.JOB_KEY,quartzJob);
scheduler.rescheduleJob(triggerKey, trigger);
// 暂停任务
if (quartzJob.getIsPause().equals(1)) {
pauseJob(quartzJob);
}
} catch (Exception e){
log.error("更新定时任务失败", e);
throw new BadRequestException("更新定时任务失败");
}
}
/**
* 删除一个job
* @param quartzJob /
*/
public void deleteJob(QuartzJob quartzJob){
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
scheduler.deleteJob(jobKey);
} catch (Exception e){
log.error("删除定时任务失败", e);
throw new BadRequestException("删除定时任务失败");
}
}
/**
* 恢复一个job
* @param quartzJob /
*/
public void resumeJob(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null) {
addJob(quartzJob);
}
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.resumeJob(jobKey);
} catch (Exception e){
log.error("恢复定时任务失败", e);
throw new BadRequestException("恢复定时任务失败");
}
}
/**
* 立即执行job
* @param quartzJob /
*/
public void runJobNow(QuartzJob quartzJob){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 如果不存在则创建一个定时任务
if(trigger == null) {
addJob(quartzJob);
}
JobDataMap dataMap = new JobDataMap();
dataMap.put(QuartzJob.JOB_KEY, quartzJob);
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.triggerJob(jobKey,dataMap);
} catch (Exception e){
log.error("定时任务执行失败", e);
throw new BadRequestException("定时任务执行失败");
}
}
/**
* 暂停一个job
* @param quartzJob /
*/
public void pauseJob(QuartzJob quartzJob){
try {
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
scheduler.pauseJob(jobKey);
} catch (Exception e){
log.error("定时任务暂停失败", e);
throw new BadRequestException("定时任务暂停失败");
}
}
}
package com.mybatisplus.job;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
@Slf4j
public class QuartzRunnable implements Callable {
private Object target;
private Method method;
private String params;
QuartzRunnable(String beanName, String methodName, String params)
throws NoSuchMethodException, SecurityException {
this.target = SpringContextHolder.getBean(beanName);
this.params = params;
if (StringUtils.isNotBlank(params)) {
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
} else {
this.method = target.getClass().getDeclaredMethod(methodName);
}
}
@Override
public Object call() throws Exception {
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotBlank(params)) {
method.invoke(target, params);
} else {
method.invoke(target);
}
return null;
}
}
package com.mybatisplus.job;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
@Slf4j
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
}
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
private static void clearHolder() {
log.debug("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext);
applicationContext = null;
}
@Override
public void destroy(){
SpringContextHolder.clearHolder();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringContextHolder.applicationContext != null) {
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
}
SpringContextHolder.applicationContext = applicationContext;
}
}
package com.mybatisplus.job.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class VisitsTask {
public void run(String str){
log.info("进入定时任务 -------------------------------> 【" + str + "】");
}
}
Controller
package com.mybatisplus.controller;
import com.mybatisplus.entity.QuartzJob;
import com.mybatisplus.job.QuartzManage;
import com.mybatisplus.mapper.QuartzJobMapper;
import com.mybatisplus.utils.ResponseEntityT;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* @description:动态定时器
* @modified By:
* @version: 1.0$
*/
@Api(tags="动态定时器")
@RestController
@RequestMapping("/job")
public class JobController {
@Autowired
private QuartzJobMapper quartzJobMapper;
@Autowired
private QuartzManage quartzManage;
/**
* @return
*/
@ApiOperation(value="定时器列表-列表查询", notes="定时器列表")
@GetMapping(value = "/list")
public ResponseEntityT<List<QuartzJob>> queryPageList() {
return ResponseEntityT.OK(quartzJobMapper.getList());
}
/**
* 添加
* @param quartzJob
* @return
*/
@ApiOperation(value="添加", notes="添加")
@PostMapping(value = "/add")
public ResponseEntityT<?> add(@RequestBody QuartzJob quartzJob,HttpServletRequest req) {
quartzJob.setIsPause(0);
quartzJobMapper.insert(quartzJob);
quartzManage.addJob(quartzJob);
return ResponseEntityT.OK("添加成功!");
}
/**
* 暂停/启动/删除
* @param quartzJob
* @return
*/
@ApiOperation(value="暂停/启动/删除", notes="isPause = 1 暂停 2.立即启动 3.删除 0.恢复")
@PutMapping(value = "/edit")
public ResponseEntityT<?> edit(@RequestBody QuartzJob quartzJob) {
QuartzJob findQuartzJob = quartzJobMapper.selectById(quartzJob.getId());
if(quartzJob==null) {
return ResponseEntityT.error("未找到对应数据");
}
if(quartzJob.getIsPause() == 0){
quartzManage.resumeJob(findQuartzJob);
findQuartzJob.setIsPause(0);
quartzJobMapper.updateById(findQuartzJob);
}
if(quartzJob.getIsPause() == 1){
quartzManage.pauseJob(findQuartzJob);
findQuartzJob.setIsPause(1);
quartzJobMapper.updateById(findQuartzJob);
}
if(quartzJob.getIsPause() == 2){
quartzManage.runJobNow(findQuartzJob);
}
if(quartzJob.getIsPause() == 3){
quartzManage.deleteJob(findQuartzJob);
quartzJobMapper.deleteById(findQuartzJob);
}
return ResponseEntityT.OK("操作成功!");
}
}
源码地址:https://gitee.com/tangzhengfeng_admin/mybatis-plus-job-quickstart