Timing tasks are also very important in our project development. For some scenarios, timing tasks must be used, such as sending emails regularly, timing statistics, etc. This article mainly talks about several ways to implement timing tasks in projects.
1. Annotation-based
This method is very simple, the main thing is to first enable the scheduled task function with @EnableScheduling, and then add @Scheduled() to the corresponding method and write the corresponding cron expression in the middle. Examples are as follows:
schedule.ScheduleTask:
java copy code import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Component @EnableScheduling //Enable scheduled tasks public class ScheduleTask { @Scheduled(cron = "0/5 * * * * ?") //Timed task annotation + cron expression public void testScheduleTask() { System.out.println("Execute scheduled tasks" + LocalDateTime.now()); } }
Cron expression parameter reference:
- Seconds (0~59) For example, 0/5 means every 5 seconds
- points (0~59)
- hour (0~23)
- A certain day of the day (0~31), needs to be calculated
- month (0~11)
- Day of the week (can fill in 1-7 or SUN/MON/TUE/WED/THU/FRI/SAT)
Suggestion: It is more convenient to directly generate Cron expressions online: www.matools.com/cron/
@Scheduled: In addition to supporting the flexible parameter expression cron, it also supports delayed operations such as fixedDelay, fixedRate, and initialDelay.
The basic timing task function is realized by starting the test, but if we modify the cron expression, we need to restart the entire application to take effect, which is not very convenient. If you want to modify the cron expression to take effect, you need to use the interface to implement timing tasks.
2. Interface-based
The way of the interface is that we put the timing task information in the database, and the program pulls the timing task information from the database, such as cron expressions, to realize real-time modification and other functions.
1. First create a table in the database to record scheduled tasks
sql copy code CREATE TABLE `scheduled` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) NULL, `cron` varchar(255) NULL, PRIMARY KEY (`id`) ) INSERT INTO `mydb`.`scheduled` (`id`, `name`, `cron`) VALUES (1, 'timed task 1', '0/6 * * * * ?')
2. Introduce the corresponding dependency packages of mabatis-plus and mysql into the project
xmlCopy code<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.32</version> </dependency>
3. Configure the connection database in application.yml
yml copy code spring: datasource: url: jdbc:mysql://localhost:3306/mydb?characterEncoding=utf-8 & serverTimeZone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver
4. Define the mapper for querying cron expressions
mapper.CronMapper:
java copy code import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; @Mapper public interface CronMapper { @Select("select cron from scheduled where id=#{id}") String getCron(Long id); }
5. Implement timing tasks
java copy code import com.jk.mapper.CronMapper; import org.springframework.beans.factory.annotation.Autowired; 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.stereotype.Component; @Component @EnableScheduling //Enable scheduled tasks public class ScheduleTask implements SchedulingConfigurer { @Autowired private CronMapper cronMapper; @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.addTriggerTask( //Add task content () -> process(), //Set the execution cycle triggerContext -> { //Query cron expression String cron = cronMapper. getCron(1L); if (cron. isEmpty()) { System.out.println("cron is null"); } return new CronTrigger(cron).nextExecutionTime(triggerContext); }); } private void process() { System.out.println("Interface-based timing task"); } }
This method needs to implement the SchedulingConfigurer interface and rewrite the configureTasks method, then set the task content and execution cycle, etc., and start the test to realize the timing task based on the interface. At this time, we change the cron expression in the database and it will take effect in real time.
3. Multi-thread timing task
But there is a problem with the timed task defined by the above method, that is, if I execute complex logic in a timed task, what should I do if the execution time exceeds the interval time of the timed task? At this time, certain problems will arise in the execution of scheduled tasks. The details are as follows. I use thread sleep to simulate and process complex logic.
java copy code import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @Component @EnableScheduling //Enable scheduled tasks public class ScheduleTask { @Scheduled(cron = "0/5 * * * * ?") //Timed task annotation + cron expression public void testScheduleTask1() throws InterruptedException { System.out.println("Execute scheduled task 1 " + LocalDateTime.now()); Thread. sleep(10 * 1000); } @Scheduled(cron = "0/5 * * * * ?") //Timed task annotation + cron expression public void testScheduleTask2() { System.out.println("Execute scheduled task 2 " + LocalDateTime.now()); } }
It can be seen that the execution time of the two tasks has been affected, which does not correspond to the 5 seconds we set. At this point, you can use multi-threaded timing tasks
java copy code 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; @Component @EnableScheduling //Enable scheduled tasks @EnableAsync //Enable multi-threading public class ScheduleTask { @Scheduled(cron = "0/5 * * * * ?") //Timed task annotation + cron expression @Async public void testScheduleTask1() throws InterruptedException { System.out.println("Execute scheduled task 1 " + LocalDateTime.now()); Thread. sleep(10 * 1000); } @Scheduled(cron = "0/5 * * * * ?") //Timed task annotation + cron expression @Async public void testScheduleTask2() { System.out.println("Execute scheduled task 2 " + LocalDateTime.now()); } }
In this way, multi-threaded timing tasks are realized, and each timing task will not affect each other, and the execution time of timing tasks will not be affected if it takes too long.