demand

You can dynamically add scheduled tasks without restarting services

The effect

Start the project (with an existing scheduled task)

Example Add a scheduled task

View console (dynamic add time task)

Implementation steps

Pom.xml introduces dependencies

Many dependencies can be removed by themselves, mainly: spring-boot-starter-Quartz


      
<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 - the 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 timed task -->
        <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>
Copy the code

Yml adds thread pool configuration

Task: pool size:10# maximum number of threads max-pool-size:30Keep-alive-seconds: keep-alive-seconds60# queue-capacity:50
Copy the code

Database file

/* 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 Name ',
  `cron_expression` varchar(32) DEFAULT NULL COMMENT 'Cron expression',
  `is_pause` int(11) DEFAULT NULL COMMENT 'Status: 1 suspended, 0 enabled',
  `job_name` varchar(32) DEFAULT NULL COMMENT 'Task Name',
  `method_name` varchar(32) DEFAULT NULL COMMENT 'Method name',
  `params` varchar(500) DEFAULT NULL COMMENT 'parameters',
  `remark` varchar(500) DEFAULT NULL COMMENT 'note',
  `update_time` datetime DEFAULT NULL COMMENT 'Created or updated date'.PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of quartz_job
-- ----------------------------
INSERT INTO `quartz_job` VALUES ('1318039441581010946'.'visitsTask'.'0/1 * * * * ?'.'0'.'Update Traffic'.'run'.'1318039441581010946'.'Test data'.'the 2020-10-19 13:51:07');
INSERT INTO `quartz_job` VALUES ('1318852329113763842'.'visitsTask'.'0/1 * * * * ?'.'0'.'New timing'.'run'.'000001'.'test'.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 name',
  `create_time` datetime DEFAULT NULL COMMENT 'Creation date',
  `cron_expression` varchar(32) DEFAULT NULL COMMENT 'Cron expression',
  `exception_detail` longtext COMMENT 'Exception detail',
  `is_success` int(11) DEFAULT NULL COMMENT 'Status 1: successful 0: failed',
  `job_name` varchar(200) DEFAULT NULL COMMENT 'Task Name',
  `method_name` varchar(200) DEFAULT NULL COMMENT 'Method name',
  `params` varchar(200) DEFAULT NULL COMMENT 'parameters',
  `time` bigint(20) DEFAULT NULL COMMENT 'Elapsed time (ms)'.PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of quartz_log
-- ----------------------------
INSERT INTO `quartz_log` VALUES ('1318832884848824321'.'visitsTask'.null.'0/1 * * * * ?'.'Executed successfully'.'1'.'Update Traffic'.'run'.'1315548171037986818131039415101946'.'1');
INSERT INTO `quartz_log` VALUES ('1318832888502063106'.'visitsTask'.null.'0/1 * * * * ?'.'Executed successfully'.'1'.'Update Traffic'.'run'.'1315548171037986818131039415101946'.'2');
INSERT INTO `quartz_log` VALUES ('1318852710766067715'.'visitsTask'.null.'0/1 * * * * ?'.'Executed successfully'.'1'.'New timing'.'run'.'000001'.'1');
INSERT INTO `quartz_log` VALUES ('1318852714960371713'.'visitsTask'.null.'0/1 * * * * ?'.'Executed successfully'.'1'.'Update Traffic'.'run'.'1315548171037986818131039415101946'.'0');
INSERT INTO `quartz_log` VALUES ('1318852714960371714'.'visitsTask'.null.'0/1 * * * * ?'.'Executed successfully'.'1'.'New timing'.'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'.'[email protected]');
INSERT INTO `user` VALUES ('2'.'Jack'.'20'.'[email protected]');
INSERT INTO `user` VALUES ('3'.'Tom'.'21'.'[email protected]');
INSERT INTO `user` VALUES ('4'.'Sandy'.'22'.'[email protected]');
Copy the code

 

The code block

package com.mybatisplus.job.threadPool;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/** * Config attribute class */
@Data
@Component
@ConfigurationProperties(prefix = "task.pool")
public class AsyncTaskProperties {

    private int corePoolSize;

    private int maxPoolSize;

    private int keepAliveSeconds;

    private int queueCapacity;
}
Copy the code
package com.mybatisplus.job.threadPool;

import org.springframework.stereotype.Component;

import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

/** * Custom thread name */
@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(a) {
        this("el-pool");
    }

    private TheadFactoryName(String name){ SecurityManager s = System.getSecurityManager(); group = (s ! =null)? s.getThreadGroup() : Thread.currentThread().getThreadGroup();// In this case, namePrefix is the name + the number of threads that use this factory to create the pool
        this.namePrefix = name +
                POOL_NUMBER.getAndIncrement();
    }

    @Override
    public Thread newThread(Runnable r) {
        // The name of the thread is namePrefix + -thread- + the number of threads executing in the thread pool
        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); }returnt; }}Copy the code
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;

/** * to get a custom thread pool */
public class ThreadPoolExecutorUtil {

    public static ThreadPoolExecutor getPoll(a){
        AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class);
        return new ThreadPoolExecutor(
                properties.getCorePoolSize(),
                properties.getMaxPoolSize(),
                properties.getKeepAliveSeconds(),
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(properties.getQueueCapacity()),
                newTheadFactoryName() ); }}Copy the code
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;

    /** * only for reference */
    private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();


    @Override
    @SuppressWarnings("unchecked")
    protected void executeInternal(JobExecutionContext context) {
        QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
        // Get the 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 {
            // Execute the task
            logger.info("Task ready to execute, task name: {}", quartzJob.getJobName());
            QuartzRunnable task = newQuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),quartzJob.getParams()); Future<? > future = EXECUTOR.submit(task); future.get();long times = System.currentTimeMillis() - startTime;
            log.setTime(times);
            // Task status
            log.setIsSuccess(1);
            log.setExceptionDetail("Executed successfully");
            logger.info("Task completed, task name: {} Total time: {} ms", quartzJob.getJobName(), times);
        }  catch (Exception e) {
            logger.info("Task execution failed. Failure cause {}",e.getMessage());
            long times = System.currentTimeMillis() - startTime;
            log.setTime(times);
            // Task status 1: succeeded 0: failed
            log.setIsSuccess(0);
            log.setExceptionDetail("Timed execution failed");
            quartzJob.setIsPause(1);
            try {
                JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
                scheduler.pauseJob(jobKey);
            } catch (Exception ee){
                logger.info("Failed to suspend scheduled task {}",ee.getMessage());
                throw new BadRequestException("Failed to suspend scheduled task");
            }
            // Update the status
            quartzJobMapper.updateById(quartzJob);
        }  finally{ quartzLogMapper.insert(log); }}}Copy the code
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;

    /** * only for reference */
    private final static ThreadPoolExecutor EXECUTOR = ThreadPoolExecutorUtil.getPoll();


    @Override
    @SuppressWarnings("unchecked")
    protected void executeInternal(JobExecutionContext context) {
        QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
        // Get the 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 {
            // Execute the task
            logger.info("Task ready to execute, task name: {}", quartzJob.getJobName());
            QuartzRunnable task = newQuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),quartzJob.getParams()); Future<? > future = EXECUTOR.submit(task); future.get();long times = System.currentTimeMillis() - startTime;
            log.setTime(times);
            // Task status
            log.setIsSuccess(1);
            log.setExceptionDetail("Executed successfully");
            logger.info("Task completed, task name: {} Total time: {} ms", quartzJob.getJobName(), times);
        }  catch (Exception e) {
            logger.info("Task execution failed. Failure cause {}",e.getMessage());
            long times = System.currentTimeMillis() - startTime;
            log.setTime(times);
            // Task status 1: succeeded 0: failed
            log.setIsSuccess(0);
            log.setExceptionDetail("Timed execution failed");
            quartzJob.setIsPause(1);
            try {
                JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
                scheduler.pauseJob(jobKey);
            } catch (Exception ee){
                logger.info("Failed to suspend scheduled task {}",ee.getMessage());
                throw new BadRequestException("Failed to suspend scheduled task");
            }
            // Update the status
            quartzJobMapper.updateById(quartzJob);
        }  finally{ quartzLogMapper.insert(log); }}}Copy the code
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;

    /** * Reactivate enabled scheduled tasks * when the project starts@param applicationArguments /
     */
    @Override
    public void run(ApplicationArguments applicationArguments){
        printSingleColor("".31.1."-------------------- Inject scheduled task ---------------------");
        printSingleColor("".1.1."");
        List<QuartzJob> quartzJobs = quartzJobMapper.getList();
        quartzJobs.stream().forEach(x ->{
            printSingleColor("".32.1."Injection -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - >" + x.getJobName());
            printSingleColor("".1.1."");
        });
        quartzJobs.forEach(quartzManage::addJob);
        printSingleColor("".34.1."-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- timing injection task -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
        printSingleColor("".1.1."");
    }
    / * * * *@paramSuch as "==============" *@paramColor code: background color code (41-46); Foreground code (31-36) *@paramN Number +m: 1 bold; 3 in italics; 4 underline *@paramContent Content to print */
    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); }}Copy the code
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;

/** * Scheduled task configuration *@author/ * /
@Configuration
public class QuartzConfig {

	/** * Solve the problem of injecting null Spring Bean into Job */
	@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 {
			// Call the method of the parent class
			Object jobInstance = super.createJobInstance(bundle);
			capableBeanFactory.autowireBean(jobInstance);
			returnjobInstance; }}/** * Inject scheduler into 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();
		returnscheduler; }}Copy the code
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 {
            // Build job information
            JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).
                    withIdentity(JOB_NAME + quartzJob.getId()).build();

            // Create Trigger with the Trigger name and cron expression
            Trigger cronTrigger = newTrigger()
                    .withIdentity(JOB_NAME + quartzJob.getId())
                    .startNow()
                    .withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
                    .build();

            cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);

            // Reset the boot time
            ((CronTriggerImpl)cronTrigger).setStartTime(new Date());

            // Perform scheduled tasks
            scheduler.scheduleJob(jobDetail,cronTrigger);

            // Pause the task
            if (quartzJob.getIsPause().equals(1)) { pauseJob(quartzJob); }}catch (Exception e){
            log.error(Failed to create a scheduled task, e);
            throw new BadRequestException(Failed to create a scheduled task); }}/** * Update the job cron expression *@param quartzJob /
     */
    public void updateJobCron(QuartzJob quartzJob){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // Create a scheduled task if it does not exist
            if(trigger == null){
                addJob(quartzJob);
                trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            }
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
            // Reset the boot time
            ((CronTriggerImpl)trigger).setStartTime(new Date());
            trigger.getJobDataMap().put(QuartzJob.JOB_KEY,quartzJob);

            scheduler.rescheduleJob(triggerKey, trigger);
            // Pause the task
            if (quartzJob.getIsPause().equals(1)) { pauseJob(quartzJob); }}catch (Exception e){
            log.error("Failed to update the scheduled task", e);
            throw new BadRequestException("Failed to update the scheduled task"); }}/** * Delete a 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(Failed to delete a scheduled task, e);
            throw new BadRequestException(Failed to delete a scheduled task); }}/** * Restore a job *@param quartzJob /
     */
    public void resumeJob(QuartzJob quartzJob){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // Create a scheduled task if it does not exist
            if(trigger == null) {
                addJob(quartzJob);
            }
            JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
            scheduler.resumeJob(jobKey);
        } catch (Exception e){
            log.error("Failed to restore scheduled task", e);
            throw new BadRequestException("Failed to restore scheduled task"); }}/** * Execute job * immediately@param quartzJob /
     */
    public void runJobNow(QuartzJob quartzJob){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // Create a scheduled task if it does not exist
            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("Scheduled task execution failed", e);
            throw new BadRequestException("Scheduled task execution failed"); }}/** * Suspends a 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("Failed to suspend scheduled task", e);
            throw new BadRequestException("Failed to suspend scheduled task"); }}}Copy the code
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(a) throws Exception {
		ReflectionUtils.makeAccessible(method);
		if (StringUtils.isNotBlank(params)) {
			method.invoke(target, params);
		} else {
			method.invoke(target);
		}
		return null; }}Copy the code
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;

    /** * Takes the Bean from the static variable applicationContext and automatically transforms it to the type of the assigned object
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        assertContextInjected();
        return (T) applicationContext.getBean(name);
    }

    /** * Takes the Bean from the static variable applicationContext and automatically transforms it to the type of the assigned object
    public static <T> T getBean(Class<T> requiredType) {
        assertContextInjected();
        return applicationContext.getBean(requiredType);
    }

    /** * Check that ApplicationContext is not empty
    private static void assertContextInjected(a) {
        if (applicationContext == null) {
            throw new IllegalStateException("ApplicaitonContext property not injected, please use applicationContext" +
                    "Define SpringContextHolder in.xml or register SpringContextHolder in the SpringBoot boot class."); }}/** * Clears SpringContextHolder ApplicationContext to Null. */
    private static void clearHolder(a) {
        log.debug("Clear ApplicationContext in SpringContextHolder :"
                + applicationContext);
        applicationContext = null;
    }

    @Override
    public void destroy(a){
        SpringContextHolder.clearHolder();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if(SpringContextHolder.applicationContext ! =null) {
            log.warn("SpringContextHolder ApplicationContext is overwritten. The original ApplicationContext is :"+ SpringContextHolder.applicationContext); } SpringContextHolder.applicationContext = applicationContext; }}Copy the code
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("Enter scheduled task -------------------------------> [" + str + "】"); }}Copy the code

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: Dynamic timer *@modified By:
 * @version: 1.0 $* /
@API (tags=" dynamic timer ")
@RestController
@RequestMapping("/job")
public class JobController {

    @Autowired
    private QuartzJobMapper quartzJobMapper;

    @Autowired
    private QuartzManage quartzManage;

    / * * *@return* /
    @apiOperation (value=" timer list - list query ", notes=" timer list ")
    @GetMapping(value = "/list")
    public ResponseEntityT<List<QuartzJob>> queryPageList() {
        return ResponseEntityT.OK(quartzJobMapper.getList());
    }

    /** * add *@param quartzJob
     * @return* /
    @apiOperation (value=" add ", notes=" add ")
    @PostMapping(value = "/add")
    publicResponseEntityT<? > add(@RequestBody QuartzJob quartzJob,HttpServletRequest req) {
        quartzJob.setIsPause(0);
        quartzJobMapper.insert(quartzJob);
        quartzManage.addJob(quartzJob);
        return ResponseEntityT.OK("Added successfully!");
    }
    /** * pause/start/delete *@param quartzJob
     * @return* /
    @apiOperation (value=" pause/start/delete ", notes="isPause = 1 Pause 2. Start now 3. Delete 0. Restore ")
    @PutMapping(value = "/edit")
    publicResponseEntityT<? > edit(@RequestBody QuartzJob quartzJob) {
        QuartzJob findQuartzJob = quartzJobMapper.selectById(quartzJob.getId());
        if(quartzJob==null) {
            return ResponseEntityT.error("No corresponding data found");
        }
        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("Operation successful!"); }}Copy the code

 

Source code address:Gitee.com/tangzhengfe…