Timed tasks in SpringBoot

Posted by bynary on Tue, 11 Jan 2022 15:01:44 +0100

1, Annotation based (@ Scheduled)

  • Based on the annotation, @ Scheduled defaults to single thread. When multiple tasks are started, the execution time of the task is affected by the execution time of the previous task.

1. Create timer

  • Using SpringBoot to create timed tasks based on annotations is very simple and can be completed in a few lines of code. The code is as follows:
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableScheduling;
    import org.springframework.scheduling.annotation.Scheduled;
    
    import java.time.LocalDateTime;
    
    /**
     * @author zhaokuii11@163.com
     * @create 2022-01-11 14:53
     * @Description
     */
    @Configuration    // 1. Represents that the current class is a configuration class
    @EnableScheduling // 2. Start scheduled task
    public class StaticScheduleTask {
        //3. Add Scheduled Task
        @Scheduled(cron = "0/5 * * * * ?")
        //Or directly specify the time interval, for example: 5 seconds
        //@Scheduled(fixedRate=5000)
        private void configureTask() {
            System.out.println("Time to execute static scheduled tasks" + LocalDateTime.now());
        }
    }
    

1.2 Cron expression parameters respectively represent:

  1. Seconds (0 ~ 59), for example, 0 / 5 means every 5 seconds
  2. Min (0 ~ 59)
  3. Time (0 ~ 23)
  4. Day (0 ~ 31), to be calculated
  5. Month (0 ~ 11)
  6. Day of week (1-7 or SUN/MON/TUE/WED/THU/FRI/SAT can be filled)
  • @Scheduled: in addition to the flexible parameter expression cron, it also supports simple delay operations, such as fixedDelay and fixedRate. Fill in the corresponding milliseconds.
    # Cron expression example:
    Every 5 seconds:*/5 * * * * ?
    Every 1 minute: 0 */1 * * * ?
    Execute once at 23:00 every day: 0 0 23 * * ?
    Execute once every day at 1 a.m.: 0 0 1 * * ?
    Execute once at 1 a.m. on the 1st of each month: 0 0 1 1 * ?
    Execute once at 23:00 on the last day of each month: 0 0 23 L * ?
    Once every Sunday at 1 a.m.: 0 0 1 ? * L
     Once at 26, 29 and 33 points: 0 26,29,33 * * * ?
    At 0:00, 13:00, 18:00 and 21:00 every day: 0,13,18,21 * * ?
    
  • More detailed cron parameters
    https://blog.csdn.net/Qiwan2/article/details/89848298
    https://blog.csdn.net/weixin_30720461/article/details/91388486

2, Interface based (schedulingconfigurator)

  • Read the specified time from the database to dynamically execute the scheduled task. At this time, the interface based scheduled task comes in handy.
  • Interface based (schedulingconfigurator)

2.1 dependency

    <!--web starter-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--add to MySql rely on -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.45</version>
        <scope>runtime</scope>
    </dependency>
    <!--jdbc-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <!--add to Mybatis Dependency configuration mybatis Some initialization things-->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>

2.2 creating database

  • Open the local database mysql, open the query window casually, and then execute the script as follows:
DROP DATABASE IF EXISTS `socks`;
CREATE DATABASE `socks`;
USE `SOCKS`;
DROP TABLE IF EXISTS `cron`;
CREATE TABLE `cron`  (
  `cron_id` varchar(30) NOT NULL PRIMARY KEY,
  `cron` varchar(30) NOT NULL  
);
INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');
# Connection parameter configuration
spring.datasource.url=jdbc:mysql://localhost:3306/socks
spring.datasource.password=root
spring.datasource.username=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

2.3 create timer

  • After the database has prepared the data, we write the scheduled task. Note that the trigger task is added here to cycle read the execution cycle set in the database and the contents of the related scheduled tasks.
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * @author zhaokuii11@163.com
 * @create 2022-01-11 15:10
 * @Description
 */
@Configuration    //1. It is mainly used to mark configuration classes and has the effect of Component
@EnableScheduling //2. Start scheduled task
public class DynamicScheduleTask implements SchedulingConfigurer {
    @Mapper
    public interface CronMapper {
        @Select("select cron from cron limit 1")
        public String getCron();
    }

    @Resource
    CronMapper cronMapper;

    /**
     * Perform scheduled tasks
     *
     * @param scheduledTaskRegistrar
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(
                //1. Add task content (Runnable)
                () -> System.out.println("Dynamic scheduled tasks:" + LocalDateTime.now().toLocalTime()),
                //2. Set the execution cycle (Trigger)
                triggerContext -> {
                    //2.1 obtaining execution cycle from database
                    String cron = cronMapper.getCron();
                    //2.2 validity verification
                    if (StringUtils.isEmpty(cron)) {
                        // Omitted Code ...
                    }
                    //2.3 return execution cycle (Date)
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                });
    }
}

2.4 start up test

  • After starting the application, check the console. The printing time is every 5 seconds as expected:
  • Note: if the format is wrong when modifying the database, the scheduled task will stop, that is, the modification is correct again; You can only restart the project to recover at this time.

3, Setting multithreaded scheduled tasks based on annotations

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * @author zhaokuii11@163.com
 * @create 2022-01-11 18:55
 * @Description
 */
@Component //@The Component annotation is used to annotate relatively neutral classes
@EnableScheduling //1. Start scheduled task
@EnableAsync //2. Enable multithreading
public class MultithreadScheduleTask {

    @Async//3. @Async can define a thread task
    @Scheduled(fixedDelay = 1000)
    public void first() throws InterruptedException {
        System.out.println("The first scheduled task starts" + LocalDateTime.now().toLocalTime());
        Thread.sleep(1000 * 10);
    }

    @Async
    @Scheduled(fixedDelay = 1000)
    public void second() throws InterruptedException {
        System.out.println("The second scheduled task starts" + LocalDateTime.now().toLocalTime());
        System.out.println();
    }

}

  • It can be seen from the console that the first scheduled task and the second scheduled task do not affect each other;
    Moreover, since multithreading is enabled, the execution time of the first task is not limited by its own execution time, so it should be noted that repeated operations may lead to data exceptions.

reference resources