SoFunction
Updated on 2025-04-27

Springboot uses Scheduling to implement dynamic addition, deletion, start and stop timed tasks

During the project development process, if it is some simple engineering or non-distributed engineering, we can generally use the @EnableScheduling annotation and the @Scheduled annotation to implement simple timing tasks, or we can use the SchedulingConfigurer interface to implement timing tasks. So how to dynamically generate timing tasks?

The following are specific steps. You can combine the database to store parameter data required for timing tasks, such as the name of the bean, method name, method parameters, executed expressions, etc.

1. Configure the thread pool required for timing tasks

import ;
import ;
import ;
import ;

// Configure the timed task thread pool@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-test-");
        return taskScheduler;
    }
}

2. Create a package class for ScheduledFuture

//ScheduledFuture's packaging classpublic final class ScheduledTask {

    volatile ScheduledFuture<?> future;

    /**
      * Cancel the scheduled task
      */
    public void cancel() {
        ScheduledFuture<?> future = ;
        if (future != null) {
            (true);
        }
    }
}

3. Register timed tasks, add and delete tasks

/**
  * Add timed task registration to add and delete timed tasks.
  */
@Component
public class CronTaskRegistrar implements DisposableBean {

    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);

    @Autowired
    private TaskScheduler taskScheduler;

    public TaskScheduler getScheduler() {
        return ;
    }

    // Add timed tasks    public void addCronTask(Runnable task, String cronExpression) {
        addCronTask(new CronTask(task, cronExpression));
    }

    // Add timed tasks    public void addCronTask(CronTask cronTask) {
        if (cronTask != null) {
            Runnable task = ();
            if ((task)) {
                removeCronTask(task);
            }

            (task, scheduleCronTask(cronTask));
        }
    }
    // Remove timing tasks    public void removeCronTask(Runnable task) {
        ScheduledTask scheduledTask = (task);
        if (scheduledTask != null)
            ();
    }

    public ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask();
         = ((), ());

        return scheduledTask;
    }


    @Override
    public void destroy() {
        for (ScheduledTask task : ()) {
            ();
        }
        ();
    }
}

4. Create a class that executes the method in the bean

// Add 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.@Slf4j
public class SchedulingRunnable implements Runnable {

    // bean name    private String beanName;

    // Method name    private String methodName;

    // Method parameters    private 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 () &&
                    () &&
                     == null;
        }

        return () &&
                () &&
                ();
    }

    @Override
    public int hashCode() {
        if (params == null) {
            return (beanName, methodName);
        }

        return (beanName, methodName, params);
    }
}

5. Get bean from spring container

// Get bean from spring container@Component
public class SpringContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
         = applicationContext;
    }

    public static Object getBean(String name) {
        return (name);
    }

    public static <T> T getBean(Class<T> requiredType) {
        return (requiredType);
    }

    public static <T> T getBean(String name, Class<T> requiredType) {
        return (name, requiredType);
    }

    public static boolean containsBean(String name) {
        return (name);
    }

    public static boolean isSingleton(String name) {
        return (name);
    }

    public static Class<? extends Object> getType(String name) {
        return (name);
    }
}

6. Create specific execution beans and methods

// Test class@Component("testTask")
public class TestTask {

    /**
      * There are ginseng methods
      * @param params
      */
    public void taskWithParams(String params) {
        ("Execute sample task with parameters:" + params);
    }

    /**
      * No misery method
      */
    public void taskNoParams() {
        ("Execute sample task without parameters");
    }
}

7. Interface testing class

@RestController
@RequestMapping("/test")
public class TestController {

    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;

    @RequestMapping("/addTest")
    public String addTest(boolean flg){
        SchedulingRunnable task;
        if (flg) {
            // Create a miserable task            task = new SchedulingRunnable("testTask", "taskNoParams");
        }
        else {
            task = new SchedulingRunnable("testTask", "taskWithParams", "hello word");
        }
        (task, "0/1 * * * * *");
        return "ok";
    }

    @RequestMapping("/updateTest")
    public String updateTest(boolean flg){
        //Remove first and then add        if(flg) {
            // Create a miserable task            SchedulingRunnable task = new SchedulingRunnable("testTask", "taskNoParams");
            (task);
        }
        else {
            SchedulingRunnable task = new SchedulingRunnable("testTask", "taskWithParams", "hello word");
            (task);
        }

        SchedulingRunnable task = new SchedulingRunnable("testTask", "taskWithParams", "hello word");
        (task, "0/5 * * * * *");
        return "ok";
    }

    @RequestMapping("/delTest")
    public String delTest(){
        SchedulingRunnable task = new SchedulingRunnable("testTask", "taskNoParams");
        (task);
        return "ok";
    }

    @RequestMapping("/startTest")
    public String startTest(boolean flg){
        /**
          * The logic of the start-stop task is to create a new task or delete a task, and the parameters are consistent.
          * You can combine the database to store configuration information into the database
          */
        if(flg) {
            SchedulingRunnable task = new SchedulingRunnable("testTask", "taskNoParams");
            (task, "0/5 * * * * *");
        }
        else {
            SchedulingRunnable task = new SchedulingRunnable("testTask", "taskNoParams");
            (task);
        }
        return "ok";
    }
}

8. Combining the database, create the corresponding entity

// Timed task entity@Data
public class JobEntity {
    /**
      * Task ID
      */
    private Integer jobId;
    /**
      * bean name
      */
    private String beanName;
    /**
      * Method name
      */
    private String methodName;
    /**
      * Method parameters
      */
    private String methodParams;
    /**
      * cron expression
      */
    private String cronExpression;
    /**
      * Status (1 Normal, 0 Pause)
      */
    private Integer jobStatus;
    /**
      * Remark
      */
    private String remark;
    /**
      * Creation time
      */
    private Date createTime;
    /**
      * Update time
      */
    private Date updateTime;

}

9. Read the tasks to be performed by the database

When the program starts, read the database and create tasks to be executed

/**
  * @description: Initialize the database task, and you can load the tasks in the database when the process starts again.
  * @author: HK
  * @since: 2025/4/21 18:21
  */
@Component
@Slf4j
public class InitTask implements CommandLineRunner {

    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;

    @Override
    public void run(String... args) {
        // Initial loading of the database with normal status/* List<SysJobPO> jobList = ("1");
         if ((jobList)) {
             for (SysJobPO job : jobList) {
                 SchedulingRunnable task = new SchedulingRunnable((), (), ());
                 (task, ());
             }

             ("The timing task has been loaded...");
         }*/
    }
}

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.