Detailed Timing Tasks for SpringBoot

Posted by fisicx on Tue, 20 Aug 2019 11:40:57 +0200

Links to the original text: https://www.cnblogs.com/mmzs/p/10161936.html

Read the catalogue:

 

Read the text:

 

Preface

Using SpringBoot to create timing tasks is very simple. There are three main ways to create timing tasks at present:

  • 1. Annotation-based (@Scheduled)
  • Secondly, Scheduling Configurer believes that everyone is familiar with the former, but in practice, we often want to read the specified time from the database to dynamically perform the timing task. At this time, the timing task based on the interface comes into use.
  • Setting Multithread Timing Tasks Based on Annotations

 

I. Static: Annotation-based

By default, annotation @Scheduled is single-threaded. When multiple tasks are opened, the execution time of the task is affected by the execution time of the previous task.

1. Create timers

Using SpringBoot to create timing tasks based on annotations is very simple and can be done in a few lines of code. The code is as follows:

@Component
@Configuration      //1. Mainly used for marking up configuration classes, with the effect of Component.
@EnableScheduling   // 2. Open Timing Tasks
public class SaticScheduleTask {
    //3. Adding Timing Tasks
    @Scheduled(cron = "0/5 * * * * ?")
    //Or specify a time interval directly, for example: 5 seconds
    //@Scheduled(fixedRate=5000)
    private void configureTasks() {
        System.err.println("Execution of Static Timing Task Time: " + LocalDateTime.now());
    }
}

Cron expression parameters represent:

  • Seconds (0-59), e.g. 0/5 for every 5 seconds
  • Scores (0-59)
  • Time (0-23)
  • On a day (0-31), it needs to be calculated.
  • Month (0-11)
  • Weekly (1-7 or SUN/MON/TUE/WED/THU/FRI/SAT)

@ Scheduled: In addition to supporting flexible parameter expression cron, it also supports simple delay operations, such as fixedDelay, fixedRate, to fill in the corresponding milliseconds.

2. Start-up test

Starting the application, you can see that the console prints the following information:

 

Obviously, it's convenient to use the @Scheduled annotation, but the disadvantage is that when we adjust the execution cycle, we need to restart the application to take effect, which is somewhat inconvenient. In order to achieve real-time effect, the interface can be used to complete the timing task.

II. Dynamics: Interface-based

Scheduling Configurer

1. Import dependency packages:

 

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>

    <dependencies>
        <dependency><!--Add to Web rely on -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency><!--Add to MySql rely on -->
             <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency><!--Add to Mybatis Dependency configuration mybatis Something initialized-->
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency><!-- Add to mybatis rely on -->
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

2. Add database records:

Open the local database mysql, open the query window at will, and then execute the script content, 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 * * * * ?');

 

Then add data sources to application.yml in the project:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/socks
    username: root
    password: 123456

 

3. Create timers

When the database is ready for data, we write a timing task. Note that TriggerTask is added here. The purpose is to read the execution cycle we set in the database and to perform the relevant timing tasks.
The code is as follows:

 

@Component
@Configuration      //1. Mainly used for marking up configuration classes, with the effect of Component.
@EnableScheduling   // 2. Open Timing Tasks
public class DynamicScheduleTask implements SchedulingConfigurer {

    @Mapper
    public interface CronMapper {
        @Select("select cron from cron limit 1")
        public String getCron();
    }

    @Autowired      //Injection mapper
    @SuppressWarnings("all")
    CronMapper cronMapper;

    /**
     * Perform scheduled tasks.
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        taskRegistrar.addTriggerTask(
                //1. Adding task content (Runnable)
                () -> System.out.println("Perform dynamic timing tasks: " + LocalDateTime.now().toLocalTime()),
                //2. Setting up the execution cycle (Trigger)
                triggerContext -> {
                    //2.1 Get execution cycles from the database
                    String cron = cronMapper.getCron();
                    //2.2 Verification of Legitimacy.
                    if (StringUtils.isEmpty(cron)) {
                        // Omitted Code ..
                    }
                    //2.3 Return to execution cycle (Date)
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
    }

}

4. Start-up test

After launching the application, look at the console and print every 10 seconds as we expected:

Then open Navicat and change the execution cycle to run every 6 seconds, as shown in the figure:
 

Looking at the console, it is very convenient to find that the execution cycle has changed and we do not need to restart the application. As shown in the figure:
 

Note: If a format error occurs when the database is modified, the timing task will stop, even if the modification is correct; only restarting the project can restore at this time.

Multithread Timing Tasks

Setting Multithread Timing Tasks Based on Annotations

1. Create multithreaded timing tasks

//@ Component annotations are used to annotate more neutral classes.
//Relatively, classes in the hierarchy are annotated by @Repository,@Service and @Controller in the persistence layer, business layer and control layer, respectively.
@Component
@EnableScheduling   // 1. Open Timing Tasks
@EnableAsync        // 2. Open multithreading
public class MultithreadScheduleTask {

        @Async
        @Scheduled(fixedDelay = 1000)  //Interval of 1 second
        public void first() throws InterruptedException {
            System.out.println("The first scheduled task begins : " + LocalDateTime.now().toLocalTime() + "\r\n thread : " + Thread.currentThread().getName());
            System.out.println();
            Thread.sleep(1000 * 10);
        }

        @Async
        @Scheduled(fixedDelay = 2000)
        public void second() {
            System.out.println("The second scheduled task begins : " + LocalDateTime.now().toLocalTime() + "\r\n thread : " + Thread.currentThread().getName());
            System.out.println();
        }
    }

 

 

2. Start-up test

After starting the application, check the console:
 

From the console, it can be seen that the first timing task and the second timing task do not affect each other.

Moreover, since multithreading is enabled and the execution time of the first task is not limited by its own execution time, it should be noted that duplicate operations may lead to data anomalies.

 

Code address: https://github.com/mmzsblog/springboot-schedule

Topics: Database Mybatis Spring MySQL