SoFunction
Updated on 2025-03-03

Summary of several ways to create dynamic timing tasks in SpringBoot

1. Use @Scheduled annotation

@Scheduled is an annotation provided by Spring to mark methods that require timed execution. Common properties include:

  • cron: Define the execution time of a task through a Cron expression.
  • fixedRate: Defines the fixed execution frequency of a task in milliseconds.
  • fixedDelay: Defines how many milliseconds the task is delayed after the previous execution is completed.

Code example:

import ;
import ;
 
@Component
public class ScheduledTasks {
 
    @Scheduled(cron = "0 0 * * * ?") // Execute once every hour    public void reportCurrentTime() {
        ("Current time:" + ());
    }
 
    @Scheduled(fixedRate = 5000) // Execute every 5 seconds    public void fixedRateTask() {
        ("Task every 5 seconds:" + ());
    }
 
    @Scheduled(fixedDelay = 7000) // Delay 7 seconds after the previous execution is completed    public void fixedDelayTask() {
        ("Execute task after 7 seconds delay:" + ());
    }
}

@Scheduled is suitable for most simple timing task scenarios, such as sending emails regularly or generating reports. However, its flexibility is poor and may not be applicable for complex task scheduling needs or scenarios where task time needs to be dynamically adjusted.

2. Use SchedulingConfigurer interface

The SchedulingConfigurer interface allows us to programmatically configure the Task Scheduler. By implementing this interface, we can flexibly set tasks' scheduling rules, and even dynamically add or remove tasks.

Simple code:

public class TaskConfig implements SchedulingConfigurer {
    
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        (
                //1. Add task content (Runnable)                () -> ("Execute timing task 2: " + ().toLocalTime()),
                //2. Set the execution cycle (Trigger)                triggerContext -> {
                    //2.1 Get execution cycle from the database                    String cron = ();
                    //2.2 Legality verification.                    if ((cron)) {
                        // Omitted Code ..
                    }
                    //2.3 Return to the execution cycle (Date)                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
 
    }
}

Detailed addition and deletion of this search operation:

  • Dynamic registration bean
public class ApplicationContextUtils implements ApplicationContextAware {
 
    private static ApplicationContext CONTEXT;
    /**
      * Set spring context
      * @param ctx spring context
      * @throws BeansException
      * */
    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        CONTEXT = ctx;
    }
 
    /**
      * Get the container
      * @return
      */
    public static ApplicationContext getApplicationContext() {
        return CONTEXT;
    }
 
    /**
      * Get container object
      * @param type
      * @param <T>
      * @return
      */
    public static &lt;T&gt; T getBean(Class&lt;T&gt; type) {
        return (type);
    }
 
    public static &lt;T&gt; T getBean(String name,Class&lt;T&gt; clazz){
        return (name, clazz);
    }
 
    public static Object getBean(String name){
        return (name);
    }
 
    /**
      * springboot dynamic registration bean
      * @param clazz
      * @param <T>
      * @return
      */
    public static &lt;T&gt; T register(Class&lt;T&gt; clazz) {
		ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) ();
		DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) ();
		BeanDefinitionBuilder beanDefinitionBuilder = (clazz);
        if((clazz).length &gt; 0) {
            return (clazz);
        }
		((), ());
		return (T) (());
    }
}
 
  • Mission entity
public class Job {
 
    /**
      * Task id, used for identification, and the fully qualified class name is used by default
      */
    private String jobId;
 
    /**
      * Task name, default simple class name
      */
    private String jobName;
 
    /**
      * cron expression, after modification, it will take effect
      */
    private String cron;
 
    /**
      * Task description
      */
    private String description;
 
    /**
      * Whether it is enabled, it is enabled by default, and it will take effect after modification
      */
    private boolean enable = true;
 
    /**
      * Is it waiting for the next task to be executed?
      */
    private boolean active;
    /**
      * Task Run Class
      */
    private Class&lt;? extends Runnable&gt; clazz;
}
  • Operation Class
public class JobHandler {
 
    private ScheduledTask scheduledTask;
 
    private TriggerTask triggerTask;
 
    private TriggerContext triggerContext;
}
  • Configurer
public class JobSchedulingConfigurer implements SchedulingConfigurer {
 
    private ScheduledTaskRegistrar registrar;
 
    /**
      * Thread pool task scheduler
      */
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        (().availableProcessors() / 3 + 1);
        ("TaskScheduler-");
        (true);  // Ensure that running tasks can be discarded immediately 
        taskScheduler = scheduler; // Get the handle to facilitate the later acquisition of future 
        return scheduler;
    }
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        (taskScheduler());
         = scheduledTaskRegistrar;
    }
 
    public ScheduledTaskRegistrar getRegistrar() {
        return registrar;
    }
 
    public void setRegistrar(ScheduledTaskRegistrar registrar) {
         = registrar;
    }
}
  • Add, delete, modify and check
public class SchedulerManager {
 
    /**
      * Task container
      */
    private Map&lt;Job, JobHandler&gt; tasks = new ConcurrentHashMap&lt;&gt;();
 
    /**
      * Task registration
      */
    @Autowired
    private JobSchedulingConfigurer register;
 
    /**
      * Added tasks, effective
      * @param job task entity
      * @return Return to the newly added task
      */
    public Job addJob(Job job) {
        (job, "job can't be null");
        ScheduledTaskRegistrar registrar = ();
        Runnable runnable = (());
        if(() == null || "".equals(())) {
            (().getName());
        }
        ((()), "Task[" + () + "]Already existed");
        if(() == null || "".equals(())) {
            ((()));
        }
        CronExpress cron = ((), );
        if(cron != null &amp;&amp; !"".equals(())) {
            // The annotated attributes are larger than the configuration attributes, which are convenient for debugging            (());
        }
        (true);
        (true);
        JobHandler entity = new JobHandler();
        TriggerTask triggerTask = new TriggerTask(runnable, (TriggerContext triggerContext) -&gt; {
            // This method will be entered every time the task is executed            CronTrigger trigger = new CronTrigger(());
            (triggerContext);
            return () ? (triggerContext) : null;
        });
        ScheduledTask scheduledTask = (triggerTask);
        (scheduledTask);
        (triggerTask);
        (job, entity);
        return job;
    }
 
    /**
      * Task class (the @CronExpress annotation must be marked and the Runnable interface is implemented)
      * @param clazz interface class
      * @return task object
      */
    public Job addJob(Class&lt;? extends Runnable&gt; clazz) {
        Job job = new Job();
        (clazz);
        return (job);
    }
 
    /**
      * Get the task operation object
      * @param jobId Task id
      * @return Task operation object
      */
    public JobHandler getJobHandler(String jobId) {
        return (new Job(jobId));
    }
 
    /**
      * Get the task according to the task id
      * @param jobId Task id
      * @return Task Entity
      */
    public Job getJob(String jobId) {
        (jobId, "jobId can't be null");
        Set&lt;Job&gt; jobs = ();
        if(() == 0) {
            return null;
        }
        Iterator&lt;Job&gt; iterator = ();
        while (()) {
            Job next = ();
            if((())) {
                return next;
            }
        }
        return null;
    }
 
    /**
      * Close the task (if the task is executing, wait for the task to be executed)
      * @param jobId Task id
      * @return Whether it is closed successfully
      */
    public boolean shutDown(String jobId) {
        try {
            JobHandler handler = (jobId);
            (handler, "Task[" + jobId + "]Don't exist");
            ().cancel();
            Job job = getJob(jobId);
            (false);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
 
    /**
      * Start a registered task
      * @param jobId Task id
      * @return Whether it is successfully started
      */
    public boolean startUp(String jobId) {
        try {
            JobHandler handler = (jobId);
            (handler, "Task[" + jobId + "]Don't exist");
            ().scheduleTriggerTask(());
            Job job = getJob(jobId);
            (true);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
 
    /**
      * Get all task entities
      * @return
      */
    public List&lt;Job&gt; getJobs() {
        return new ArrayList&lt;&gt;(());
    }
 
    /**
      * Delete the task, close it first and then delete it
      * @param jobId
      * @return
      */
    public boolean deleteJob(String jobId) {
        try {
            Job job = (jobId);
            (job, "Task[" + jobId + "]Don't exist");
            shutDown(jobId);
            (job);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
 
  • Task Run Class
@CronExpress("0/1 * * * * *")
public class HelloJob implements Runnable {
 
    @Override
    public void run() {
        ("hello msg" + ().getId());
    }
}
  • test
ConfigurableApplicationContext ctx = (, args);
SchedulerManager schedulerManager = ();
Job job = ();
(());

3. Use TaskScheduler

TaskScheduler is the core interface provided by Spring for scheduling tasks. Through TaskScheduler, you can flexibly arrange the execution time of tasks and can create and cancel tasks dynamically at runtime.

The code example is simple to use:

import ;
import ;
import ;
import ;
 
@Configuration
public class TaskSchedulerConfig {
 
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        (5);
        ("MyScheduler-");
        return scheduler;
    }
}

When using TaskScheduler, you can dynamically arrange tasks through the schedule method:

import ;
import ;
import ;
 
import ;
 
@Component
public class DynamicTask {
 
    @Autowired
    private TaskScheduler taskScheduler;
 
    public void scheduleTask() {
        (() -&gt; ("Dynamic task execution:" + ()), new Date(() + 5000));
    }
}

Spring boot uses TaskScheduler to implement dynamic add, delete, start and stop timing tasks

  • SchedulingConfig: Add thread pool configuration class to execute timing tasks
import ;
import ;
import ;
import ;
 
@Configuration
public class SchedulingConfig {
 
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // Number of core threads for the timed task execution thread pool        (4);
        (true);
        ("TaskSchedulerThreadPool-");
        return taskScheduler;
    }
}
  • ScheduledTask: Add the wrapper class of ScheduledFuture

ScheduledFuture is the execution result of the ScheduledExecutorService timed task thread pool.

import ;
 
public final class ScheduledTask {
 
    volatile ScheduledFuture&lt;?&gt; future;
 
    /**
      * Cancel the scheduled task
      */
    public void cancel() {
        ScheduledFuture&lt;?&gt; future = ;
        if (future != null) {
            (true);
        }
    }
}
  • SchedulingRunnable: Add Runnable interface implementation class

Added the Runnable interface implementation class, which is called by the timed task thread pool, and is used to execute the methods in the specified bean

import ;
import org.;
import org.;
import ;
 
import ;
import ;
 
public class SchedulingRunnable implements Runnable {
 
    private static final Logger logger = ();
 
    private final String beanName;
 
    private final String methodName;
 
    private final String params;
 
    public SchedulingRunnable(String beanName, String methodName) {
        this(beanName, methodName, null);
    }
 
    public SchedulingRunnable(String beanName, String methodName, String params) {
         = beanName;
         = methodName;
         = params;
    }
 
    @Override
    public void run() {
        ("Timed tasks start execution - bean:{},method:{},parameter:{}", beanName, methodName, params);
        long startTime = ();
 
        try {
            Object target = (beanName);
 
            Method method = null;
            if ((params)) {
                method = ().getDeclaredMethod(methodName, );
            } else {
                method = ().getDeclaredMethod(methodName);
            }
 
            (method);
            if ((params)) {
                (target, params);
            } else {
                (target);
            }
        } catch (Exception ex) {
            (("Timed task execution exception - bean: %s, method: %s, parameter: %s ", beanName, methodName, params), ex);
        }
 
        long times = () - startTime;
        ("Timed task execution ends - bean:{},method:{},parameter:{},time consuming:{} millisecond", beanName, methodName, params, times);
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != ()) return false;
        SchedulingRunnable that = (SchedulingRunnable) o;
        if (params == null) {
            return () &amp;&amp;
                    () &amp;&amp;
                     == null;
        }
 
        return () &amp;&amp;
                () &amp;&amp;
                ();
    }
 
    @Override
    public int hashCode() {
        if (params == null) {
            return (beanName, methodName);
        }
 
        return (beanName, methodName, params);
    }
}
  • CronTaskRegistrar: Add a timed task registration class to add and delete timed tasks
import ;
import ;
import ;
import ;
import ;
import ;
 
import .*;
import ;
 
/**
  * Add a timed task registration class to add and delete timed tasks.
  */
@Component
public class CronTaskRegistrar implements DisposableBean {
 
    private final Map&lt;Runnable, ScheduledTask&gt; scheduledTasks = new ConcurrentHashMap&lt;&gt;(16);
    private final Map&lt;Integer, ScheduleResult&gt; schedulerJob = new HashMap&lt;&gt;();
 
    @Autowired
    private TaskScheduler taskScheduler;
 
    public TaskScheduler getScheduler() {
        return ;
    }
 
    public void addCronTask(ScheduleResult scheduleResult) {
        SchedulingRunnable task = new SchedulingRunnable((), (), ());
        String cronExpression = ();
 
        CronTask cronTask = new CronTask(task, cronExpression);
        // If this task is currently included, remove        if ((task)) {
            removeCronTask((), (), ());
        }
        ((), scheduleResult);
        (task, scheduleCronTask(cronTask));
    }
 
    public void removeCronTask(String beanName, String methodName, String methodParams) {
        SchedulingRunnable task = new SchedulingRunnable(beanName, methodName, methodParams);
        ScheduledTask scheduledTask = (task);
        if (scheduledTask != null) {
            ();
        }
    }
 
    public void removeCronTask(ScheduleResult scheduleResult) {
        ((), scheduleResult);
        removeCronTask((), (), ());
    }
 
    public ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask();
         = ((), ());
        return scheduledTask;
    }
 
    public Map&lt;Runnable, ScheduledTask&gt; getScheduledTasks() {
        return scheduledTasks;
    }
 
    public Map&lt;Integer, ScheduleResult&gt; getSchedulerJob() {
        return schedulerJob;
    }
 
    @Override
    public void destroy() {
        for (ScheduledTask task : ()) {
            ();
        }
 
        ();
    }
 
    public ScheduleResult getSchedulerByJobId(Integer jobId) {
        for (ScheduleResult job : findAllTask()) {
            if ((())) {
                return job;
            }
        }
        return null;
    }
 
    public List&lt;ScheduleResult&gt; findAllTask() {
        List&lt;ScheduleResult&gt; ScheduleResults = new ArrayList&lt;&gt;();
        Set&lt;&lt;Integer, ScheduleResult&gt;&gt; entries = ();
        for (&lt;Integer, ScheduleResult&gt; en : entries) {
            (());
        }
        return ScheduleResults;
    }
}
  • CronUtils: Verify the validity of Cron expressions
import ;
 
public class CronUtils {
 
    /**
      * Return a boolean value representing the validity of a given Cron expression
      *
      * @param cronExpression Cron expression
      * @return boolean expression is valid
      */
    public static boolean isValid(String cronExpression) {
        return (cronExpression);
    }
 
}
  • ScheduleResult: Add a timed task entity class
import ;
 
@Data
public class ScheduleResult {
 
    /**
      * Task ID
      */
    private Integer jobId;
 
    /**
      * bean name
      */
    private String beanName;
 
    /**
      * Method name
      */
    private String methodName;
 
    /**
      * Method parameters: Which method in the service is executed
      */
    private String methodParams;
 
    /**
      * cron expression
      */
    private String cronExpression;
 
    /**
      * Status (1 Normal, 0 Pause)
      */
    private Integer jobStatus;
 
    /**
      * Remark
      */
    private String remark;
 
    /**
      * Creation time
      */
    private String createTime;
 
    /**
      * Update time
      */
    private String updateTime;
 
}
  • ScheduleJobStatus: Task status enumeration type
public enum ScheduleJobStatus {
 
    /**
      * pause
      */
    PAUSE,
 
    /**
      * normal
      */
    NORMAL;
 
}
  • SpringContextUtils class: Get bean from spring container
import ;
import ;
import ;
import ;
 
@Component
public class SpringContextUtils implements ApplicationContextAware {
 
    private static ApplicationContext applicationContext = null;
 
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if ( == null) {
             = applicationContext;
        }
    }
 
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
 
    // Get Bean by name.    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }
 
    // Get Bean through class.    public static &lt;T&gt; T getBean(Class&lt;T&gt; clazz) {
        return getApplicationContext().getBean(clazz);
    }
 
    // Return the specified bean via name and Clazz    public static &lt;T&gt; T getBean(String name, Class&lt;T&gt; clazz) {
        return getApplicationContext().getBean(name, clazz);
 
    }
 
    public static boolean containsBean(String name) {
        return getApplicationContext().containsBean(name);
    }
 
    public static boolean isSingleton(String name) {
        return getApplicationContext().isSingleton(name);
    }
 
    public static Class&lt;? extends Object&gt; getType(String name) {
        return getApplicationContext().getType(name);
    }
}
  • ScheduleJobService: Add or delete start and stop service methods
@Service
@Slf4j
public class ScheduleJobService {
 
    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;
 
    public void addScheduleJob(ScheduleResult scheduleResult) {
        long currentTimeMillis = ();
        (formatTimeYMD_HMS_SSS(currentTimeMillis));
        (formatTimeYMD_HMS_SSS(currentTimeMillis));
        (findAllTask().size() + 1);
        if (().equals(())) {
            ("Stop or pause: is now on");
            (scheduleResult);
            return;
        }
        ().put((), scheduleResult);
    }
 
    public void editScheduleJob(ScheduleResult currentSchedule) {
        //Remove first        ((), (), ());
        ScheduleResult pastScheduleJob = (());
        if (pastScheduleJob == null) {
            ("Not this task");
            return;
        }
        // Then determine whether it is enabled. If it is enabled, execute it now        startOrStopSchedulerJob(currentSchedule, true);
    }
 
    public void deleteScheduleJob(ScheduleResult scheduleResult) {
        // Clear this task        ((), (), ());
        // Clear data from this task        ().remove(());
    }
 
    public void startOrStopScheduler(ScheduleResult scheduleResult) {
        ().get(()).setJobStatus(());
        startOrStopSchedulerJob(scheduleResult, false);
    }
 
    private void startOrStopSchedulerJob(ScheduleResult scheduleResult, boolean update) {
        // Update time        (formatTimeYMD_HMS_SSS(()));
        if (().equals(())) {
            ("Stop or Pause: Now it's on");
            (scheduleResult);
            return;
        }
        ("Stop or pause: Now it's pause");
        if (update){
            (scheduleResult);
            return;
        }
        ((), (), ());
    }
 
    public List&lt;ScheduleResult&gt; findAllTask() {
        return ();
    }
 
 
    // Convert to year-month-day hour: minute: seconds    private String formatTimeYMD_HMS_SSS(long time) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(time);
    }
}
  • cronController: Access interface
import ;
import ;
import ;
import ;
import ;
import .*;
 
import ;
 
@RestController
public class cronController {
 
    @Autowired
    private ScheduleJobService scheduleJobService;
 
    /**
      * Test the uploaded use case file to obtain detailed execution results
      */
    @PostMapping("/add")
    void executeTestOneFile(@RequestBody ScheduleResult scheduleResult) {
        boolean valid = (());
        if (valid){
            ("Check successfully, add task");
            (()+());
            (scheduleResult);
        }else {
            ("Check failed");
        }
    }
 
    @PostMapping("/stop")
    void end(@RequestBody ScheduleResult scheduleResult) {
        Gson gson = new Gson();
        ("================");
        (scheduleResult);
        ("=================");
        (0);
        (scheduleResult);
    }
 
    @PostMapping("/start")
    void start(@RequestBody ScheduleResult scheduleResult) {
        ("================");
        (scheduleResult);
        ("=================");
        (1);
        (scheduleResult);
    }
 
    @PostMapping("/edit")
    void edit(@RequestBody ScheduleResult scheduleResult) {
        ("=======edit=========");
        (scheduleResult);
        ("=================");
        (scheduleResult);
    }
 
    @PostMapping("/delete")
    void delete(@RequestBody ScheduleResult scheduleResult) {
        ("=======delete=========");
        (scheduleResult);
        ("=================");
        (scheduleResult);
    }
 
    @GetMapping("/tasks")
    List&lt;ScheduleResult&gt; get() throws Exception {
        List&lt;ScheduleResult&gt; allTask = ();
        ("Current number of scheduled tasks = " + ());
        ("Current timing tasks = " + allTask);
        return allTask;
    }
}
  • Test bean
import ;
 
@Component
public class c1 {
    public void test1(String y){
        ("This is the bean of test1: " + y);
    }
 
    public void test2(){
        ("This is the test2 method in bean of test1");
    }
}
  • Timing tasks after project start
import ;
import ;
import ;
import ;
import ;
 
@Component
public class init  implements CommandLineRunner {
 
    @Autowired
    private ScheduleJobService scheduleJobService;
 
    @Override
    public void run(String... args) throws Exception {
        ("Start cherish");
        ScheduleResult scheduleResult = new ScheduleResult();
        ("c1");
        ("test1");
        ("0/25 * * * * *");
        (1);
        ("test1");
        (scheduleResult);
        ();
    }
}

4. Use Quartz to implement timing tasks

Quartz is a powerful open source task scheduling framework that supports complex task scheduling requirements, such as task persistence, distributed task management, database-based scheduling, etc. Spring Boot provides good integration with Quartz, making it easier to use Quartz in your application.

Simple use:

import .*;
import ;
import ;
import ;
import ;
 
@Configuration
public class QuartzConfig {
 
    @Bean
    public JobDetailFactoryBean jobDetail() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        ();
        ("Sample Quartz Job");
        (true);
        return factoryBean;
    }
 
    @Bean
    public SimpleTriggerFactoryBean trigger(JobDetail jobDetail) {
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        (jobDetail);
        (5000); // Execute every 5 seconds        (SimpleTrigger.REPEAT_INDEFINITELY);
        return factoryBean;
    }
 
    public static class SampleJob implements Job {
        @Override
        public void execute(JobExecutionContext context) {
            ("Quartz task execution:" + ());
        }
    }
}

springboot integration

  • Database Design

Put the task schedule into the database to save. In the startup task, you can search for task schedule information from the database and configure it dynamically.

DROP TABLE IF EXISTS `cc_task_info`;
 
CREATE TABLE `cc_task_info` (
  `TID` int(11) NOT NULL AUTO_INCREMENT,
  `TASK_ANME` varchar(50) NOT NULL,
  `TASK_CODE` varchar(50) NOT NULL,
  `JOB_CLASS` varchar(200) NOT NULL,
  `JOB_GROUP` varchar(50) NOT NULL,
  `CRON` varchar(50) NOT NULL,
  `DEL_STATUS` varchar(2) DEFAULT '1' NULL,
  `CRT_TIME` datetime DEFAULT NULL,
  PRIMARY KEY (`TID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Timed Task Management Table';
 
DROP TABLE IF EXISTS `cc_task_record`;
 
CREATE TABLE `cc_task_record` (
  `RID` int(11) NOT NULL AUTO_INCREMENT,
  `TASK_CODE` varchar(50) NOT NULL,
  `RUN_TIME` datetime NOT NULL,
  `RUN_CODE` char(1) NOT NULL,
  `RUN_MSG` varchar(100) NULL,
  PRIMARY KEY (`RID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Timed task run record table';
 
DROP TABLE IF EXISTS `cc_task_status`;
 
CREATE TABLE `cc_task_status` (
  `TASK_CODE` varchar(50) NOT NULL,
  `TASK_STATUS` varchar(10) NOT NULL,
  `LST_SUCC_TIME` datetime NOT NULL,
  `LST_TIME` datetime NOT NULL,
  PRIMARY KEY (`TASK_CODE`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Timed task running status table';
  • Timing task management

Implemented through Scheduler method. Scheduler provides a series of methods to manage the execution status of a scheduled task.

Mainly including:

  • scheduleJob(): Add a timed task
  • rescheduleJob(): Modify the timing task
  • pauseJob(): Pause timed task execution
  • resumeJob(): Resuming the execution of the timed task
  • deleteJob(): Delete the execution of the timed task

For the above method, you only need to pass in the corresponding parameters. A QuartzService was built to manage timing tasks for call from the business layer.

The detailed code is as follows:

/**
  * Timing task management service
  */
@Service
public class QuartzService {
 
    public static String SCHEDULER_OPR_START = "start";
    public static String SCHEDULER_OPR_PAUSE = "pause";
    public static String SCHEDULER_OPR_RESUME = "resume";
    public static String SCHEDULER_OPR_REMOVE = "remove";
 
    @Autowired
    private Scheduler scheduler;
 
    /**
      * Start the task
      */
    public void startJob(String taskCode, String taskAnme, String cron, String jobGroup,
                         String className) throws Exception{
        Class&lt;Job&gt; jobClass = null;
        try {
            jobClass = (Class&lt;Job&gt;) (className);//Get task execution class        } catch (ClassNotFoundException e) {
            throw new Exception("Task class does not exist");
        }
        //Create job, specify job name and grouping        JobDetail jobDetail = (jobClass).withIdentity(taskCode, jobGroup).build();
        //Create an expression work plan        CronScheduleBuilder cronScheduleBuilder = (cron);
        //Create a trigger        CronTrigger cronTrigger = ().withIdentity(taskCode, jobGroup)
                .withSchedule(cronScheduleBuilder).build();
        (jobDetail, cronTrigger);
    }
 
    /**
      * Modify the execution time of the time of the scheduled task
      * @param taskCode
      * @param jobGroup
      * @param cron New time
      * @throws Exception
      */
    public void modifyJob(String taskCode, String jobGroup, String cron) throws Exception{
        TriggerKey triggerKey = new TriggerKey(taskCode, jobGroup);
        CronTrigger trigger = (CronTrigger) (triggerKey);
        String oldCron = ();
        if(!(cron)){
            CronTrigger cronTrigger = ().withIdentity(taskCode, jobGroup)
                    .withSchedule((cron)).build();
            Date date = (triggerKey, cronTrigger);
            if(date == null){
                throw new Exception("Report an error in modifying the execution time of the timing task");
            }
        }
    }
 
    /**
      * Pause a certain timed task (after the task is restored, tasks that are not executed during the pause period will continue to be executed. If there are 2 times in the pause period, they will be executed twice)
      * @param taskCode
      * @param jobGroup
      * @throws Exception
      */
    public void pauseJob(String taskCode, String jobGroup) throws Exception{
        JobKey jobKey = new JobKey(taskCode, jobGroup);
        JobDetail jobDetail = (jobKey);
        if(jobDetail == null){
            return;
        }
        (jobKey);
    }
 
    /**
      * Restoring a scheduled task
      * @param taskCode
      * @param jobGroup
      * @throws Exception
      */
    public void resumeJob(String taskCode, String jobGroup) throws Exception{
        JobKey jobKey = new JobKey(taskCode, jobGroup);
        JobDetail jobDetail = (jobKey);
        if(jobDetail == null){
            return;
        }
        (jobKey);
    }
 
    /**
      * Delete a timed task
      * @param taskCode
      * @param jobGroup
      * @throws Exception
      */
    public void deleteJob(String taskCode, String jobGroup) throws Exception{
        JobKey jobKey = new JobKey(taskCode, jobGroup);
        JobDetail jobDetail = (jobKey);
        if(jobDetail == null){
            return;
        }
        (jobKey);
    }
}
  • Write a task class JOB

Task-like JOB is the system business logic that the timing tasks need to be processed, and it needs to implement a Job interface.

When the task starts, pass in the JobDetail through the jobClass.

public class DemoJob implements Job {
 
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String taskCode = ().getKey().getName();
        ("Execute timing tasks:" + taskCode);
    }
}
  • Configure Scheduler

Configure the Scheduler instance in Configuration and start it.

@Configuration
public class QuartzConfig {
 
    @Bean
    public Scheduler scheduler(){
        Scheduler scheduler = null;
        SchedulerFactory factory = new StdSchedulerFactory();
        try {
            scheduler = ();
        } catch (SchedulerException e) {
            ();
        }
        if(scheduler != null){
            try {
                //Start the timing task                ();
            } catch (SchedulerException e) {
                ();
            }
        }
        return scheduler;
    }
}
  • Writing API interfaces

The API interface is provided through the Controller. The TaskService here calls the corresponding interface of QartzService and performs a write database read and write operation, mainly recording the timing task status, execution record information, etc.

@RestController
@RequestMapping("/api/task")
public class TaskController {
 
    @Autowired
    private TaskService service;
 
    @RequestMapping("/start")
    public Object start(int id){
        try {
            (id);
            return ();
        } catch (Exception e) {
            return (());
        }
    }
 
    @RequestMapping("/pause")
    public Object pause(int id){
        try {
            (id);
            return ();
        } catch (Exception e) {
            return (());
        }
    }
 
    @RequestMapping("/resume")
    public Object resume(int id){
        try {
            (id);
            return ();
        } catch (Exception e) {
            return (());
        }
    }
 
    @RequestMapping("/remove")
    public Object remove(int id){
        try {
            (id);
            return ();
        } catch (Exception e) {
            return (());
        }
    }
}

The above is a detailed summary of several ways to create dynamic timing tasks in SpringBoot. For more information about SpringBoot dynamic timing tasks, please pay attention to my other related articles!