Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

Background: 📅

More recently, this timed task was used in a way that simply used annotations, which had to be reworked as requirements changed.

I came up with dynamic timed tasks, connected to a database to dynamically select, and that really solved the problem.

However, there is still a defect, that is, it is impossible to set the execution time of the task. It is impossible to set the execution time to 00:00 PM when I wish XDM a birthday, like QQ send chat.

This article on the above three points with their own ideas to write a small Demo, I hope to help you.

👩 💻

Cover: from the corner of campus, autumn is getting thicker, missing is getting deeper.

Countdown pull countdown pull, XDM, National Day is coming

Preface:

Read more: 🐱👓

  1. knowSpringBootHow do you implement timed tasks with annotations
  2. understandSpringBootHow to implement a dynamic scheduled task (database associated implementation)
  3. understandSpringBootImplement set time to perform scheduled tasks (useThreadPoolTaskScheduler Implementation)

Annotations to implement scheduled tasks

Annotations are really easy to implement, as long as you know cron expressions. 🧙 came ️

Step 1: Annotate the main startup class with @enablesCheduling

@EnableScheduling
@SpringBootApplication
public class SpringBootScheduled {

    public static void main(String[] args) { SpringApplication.run(SpringBootScheduled.class); }}Copy the code

Step 2: Write a class and inject it into Spring. The key is the @Scheduled annotation. () is the cron expression used to describe the execution cycle of this method. 🛌

I can’t always remember, it’s usually generated online: Cron expressions are generated online

The value ranges from 0 to 59. The value ranges from 0 to 59. The value ranges from 0 to 23. The value ranges from 1 to 31. The value ranges from 1 to 7. 1 indicates Sunday, and 2 indicates Monday * The seventh digit. The value can be left blank@author crush
 * @since 1.0.0
 * @Date: the 2021-07-27 and * /
@Component
public class SchedulingTaskBasic {

    /** ** every five seconds */
    @Scheduled(cron = "*/5 * * * * ?" )
    private void printNowDate(a) {
        long nowDateTime = System.currentTimeMillis();
        System.out.println(Fixed scheduled task execution :-- >+nowDateTime+", this task is to be performed every five seconds"); }}Copy the code

Execution effect:

Source code at the end of the article. 🏍

2. Dynamic scheduled tasks

It’s actually very simple.

2.1. Build data tables

Step 1: Create a database table.

CREATE TABLE `tb_cron`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Dynamic Scheduled Task Schedule',
  `cron_expression` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'Scheduled task Expression',
  `cron_describe` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'description'.PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

INSERT INTO `tb_cron` VALUES (1.'0 0/1 * * * ?'.'Run every minute');
Copy the code

2.2 import dependencies and basic coding

Step 2: import database dependencies, so that you can query data from the database. Everybody can. 🤸 came ️

Step 3: Code

Entity class:

@Data
@TableName("tb_cron")
public class Cron {
    private Long id;
    private String cronExpression;
    private String cronDescribe;
}
Copy the code

Mapper layer:

@Repository
public interface CronMapper extends BaseMapper<Cron> {
    @Select("select cron_expression from tb_cron where id=1")
    String getCron1(a);
}
Copy the code

2.3. Main implementation code

Step 4: Write a class that implements SchedulingConfigurer🍻

Implement void configureTasks(ScheduledTaskRegistrar taskRegistrar) Method to register the TaskScheduler and the specific Task instance with the given ScheduledTaskRegistrar

@Component
public class CompleteScheduleConfig implements SchedulingConfigurer {

    @Autowired
    @SuppressWarnings("all")
    CronMapper cronMapper;

    /** * Performs scheduled tasks. */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(
                //1. Add task content (Runnable)
                () -> System.out.println("Execute dynamic scheduled task 1:" + LocalDateTime.now().toLocalTime()+", this task execution period is determined by the CRON expression in the database"),
                //2. Set the execution cycle (Trigger)
                triggerContext -> {
                    //2.1 Obtain the execution period from the database
                    String cron = cronMapper.getCron1();
                    2.2 Validity verification.
                    if(cron! =null) {
                        // Omitted Code ..
                    }
                    //2.3 Return to Execution Period (Date)
                    return newCronTrigger(cron).nextExecutionTime(triggerContext); }); }}Copy the code

Effect of 2.4,

Note: When you modify the execution period of a task, the execution time is after the last task. This point needs to pay attention to, using the example in life to understand that our cancellation of the phone card package will also take effect next month, the meaning is the same.

Source code is also at the end of the article.

3. Implement the scheduled task of setting time

Often the business scenario is a one-off, timed task, as DESCRIBED in my introduction. For example: I set the release time of this article I wrote for 2 o ‘clock this afternoon, the implementation of the deletion did not have. Disposable.

The implementation relies heavily on the ScheduledFuture
schedule(Runnable task, Trigger trigger); Method to implement. The essence is the same as the implementation of dynamic timed tasks.

3.1. Key points

There are annotations in the code, not much explanation.

import cn.hutool.core.convert.ConverterRegistry;
import com.crush.scheduled.entity.Task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;

/ * * *@author crush
 */
@Component
@Slf4j
public class DynamicTaskService {

    /** * The following two are thread-safe collection classes. * /
    publicMap<String, ScheduledFuture<? >> taskMap =new ConcurrentHashMap<>();
    public List<String> taskList = new CopyOnWriteArrayList<String>();


    private final ThreadPoolTaskScheduler syncScheduler;

    public DynamicTaskService(ThreadPoolTaskScheduler syncScheduler) {
        this.syncScheduler = syncScheduler;
    }

    /** * View started but not executed dynamic tasks *@return* /
    public List<String> getTaskList(a) {
        return taskList;
    }


    /** * Add a dynamic task **@param task
     * @return* /
    public boolean add(Task task) {
        // If a task with this name already exists, delete the previous one and then add the current one. (Repeat to cover)
        if (null! = taskMap.get(task.getName())) { stop(task.getName()); }// Hutool is a tool class for converting types
        ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
        Date startTime = converterRegistry.convert(Date.class, task.getStart());

        // schedule: schedules the given Runnable and calls it at the specified execution time.
        // Execution ends once the scheduler closes or the returned ScheduledFuture is cancelled.
        / / parameters:
        // Task - The Runnable that executes when the trigger fires
        //startTime - The time required for the task to execute (if this is the past, the task will execute immediately, i.e. as soon as possible)ScheduledFuture<? > schedule = syncScheduler.schedule(getRunnable(task), startTime); taskMap.put(task.getName(), schedule); taskList.add(task.getName());return true;
    }


    /** * Run the task **@param task
     * @return* /
    public Runnable getRunnable(Task task) {
        return () -> {
            log.info("-- Dynamic scheduled task running --");
            try {
                System.out.println("At this time ==>" + LocalDateTime.now());
                System.out.println("Time set in task ==>" + task);
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.info("---end--------");
        };
    }

    /** * Stop the task **@param name
     * @return* /
    public boolean stop(String name) {
        if (null == taskMap.get(name)) {
            return false; } ScheduledFuture<? > scheduledFuture = taskMap.get(name); scheduledFuture.cancel(true);
        taskMap.remove(name);
        taskList.remove(name);
        return true; }}Copy the code

3.2 configuration of asynchronous thread pools

/** * Asynchronous thread pool ThreadPoolExecutor configuration class **@Author: crush
 * @Date: when the 2021-07-23 * /
@Configuration
public class ThreadPoolTaskExecutorConfig {

    @Bean
    public ThreadPoolTaskScheduler syncScheduler(a) {
        ThreadPoolTaskScheduler syncScheduler = new ThreadPoolTaskScheduler();
        syncScheduler.setPoolSize(5);
        // The thread is given a name so that errors can be quickly located in the project.
        syncScheduler.setThreadGroupName("syncTg");
        syncScheduler.setThreadNamePrefix("syncThread-");
        syncScheduler.initialize();
        returnsyncScheduler; }}Copy the code

3.3. Business code

One thing to note here is that I cast LocalDateTime in the project. Here is not posted (mainly copy the previous code left over, the source code has)

For easy use, you can annotate the LocalDateTime property directly.

package com.crush.scheduled.controller;
import com.crush.scheduled.entity.Task;
import com.crush.scheduled.service.DynamicTaskService;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/ * * *@Author: crush
 * @Date: 2021-07-29 15:26
 * version 1.0
 */
@RestController
@RequestMapping("/dynamicTask")
public class DynamicTaskController {

    private final DynamicTaskService dynamicTask;

    public DynamicTaskController(DynamicTaskService dynamicTask) {
        this.dynamicTask = dynamicTask;
    }

    /** * View started but not executed dynamic tasks *@return* /
    @GetMapping
    public List<String> getStartingDynamicTask(a){
        return dynamicTask.getTaskList();
    }


    /** * Start a dynamic task *@param task
     * @return* /
    @PostMapping("/dynamic")
    public String startDynamicTask(@RequestBody Task task){
        // Add this to the dynamic scheduled task
        dynamicTask.add(task);
         return "Dynamic task :"+task.getName()+" 已开启";
    }


    /** * Stops a dynamic task by name *@param name
     * @return* /
    @DeleteMapping("/{name}")
    public String stopDynamicTask(@PathVariable("name") String name){
        // Add this to the dynamic scheduled task
        if(! dynamicTask.stop(name)){return "Stop failed, task already in progress.";
        }
        return "The mission has stopped."; }}Copy the code

An entity class that is simply encapsulated:

/ * * *@Author: crush
 * @Date: 2021-07-29 15:35
 * version 1.0
 */
@Data
@Accessors(chain = true) // It is convenient for chain writing
public class Task {
    /** * Dynamic task name was */
    private String name;

    /** * Set the start time of the dynamic task */
    private LocalDateTime start;
}
Copy the code

Effect of 3.4,

💫 💨

Start a dynamic task:

View dynamic tasks that have not been executed:

Execution Result:

That’s exactly what we have in our code.

Stop task:

To check is to have stopped pulling

4. Talk to yourself

Source: springboot – scheduled

This article is a brief introduction, the specific use of the specific need to be analyzed according to the specific situation.

Hello, I am Ning Jae-chun: homepage 👨💻

I hope you found this article useful!!

Wish us: by the time we meet on another day, we have achieved something. (❤ ´ 艸 ` ❤)