守时使命在咱们项目开发中也是很重要的,对于某些场景必须要用守时使命 ,如守时发送邮件啊,守时统计数据等,这篇文章首要讲讲项目中完成守时使命的几种办法。

一、根据注解

这种办法很简单,首要就是先@EnableScheduling敞开守时使命功用,然后在相应的办法上增加@Scheduled()中间写上相应的cron表达式即可。示例如下:

schedule.ScheduleTask:

import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@EnableScheduling //敞开守时使命
public class ScheduleTask {
    @Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
    public void testScheduleTask() {
        System.out.println("履行守时使命" + LocalDateTime.now());
    }
}

Cron表达式参数参考:

  • 秒(0~59) 例如0/5表示每5秒
  • 分(0~59)
  • 时(0~23)
  • 日(0~31)的某天,需计算
  • 月(0~11)
  • 周几( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)

主张:直接在线生成Cron表达式比较便利:www.matools.com/cron/

@Scheduled:除了支持灵敏的参数表达式cron之外,还支持 fixedDelayfixedRateinitialDelay 这些延时性的操作。

SpringBoot 中实现定时任务的几种方式

发动测验就完成了基本的守时使命功用,但是假如咱们修正了cron表达式,需要重启整个使用才能收效,不是很便利。想要完成修正cron表达式就收效就需要用到接口的办法来完成守时使命。

二、根据接口

接口的办法是咱们把守时使命的信息放在数据库中,程序从数据库去拉取守时使命的信息如cron表达式来完成实时修正收效等功用。

1. 首先在数据库中创建一张用来记载守时使命的表

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, '守时使命1', '0/6 * * * * ?')

2. 在项目中引入mabatis-plusmysql相应的依赖包

<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. 在application.yml中进行衔接数据库相应配置

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. 界说查询cron表达式的mapper

mapper.CronMapper:

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. 完成守时使命

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 //敞开守时使命
public class ScheduleTask implements SchedulingConfigurer {
    @Autowired
    private CronMapper cronMapper;
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(
                //增加使命内容
                () -> process(),
                //设置履行的周期
                triggerContext -> {
                    //查询cron表达式
                    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("根据接口的守时使命");
    }
}

这种办法需要去完成SchedulingConfigurer接口并重写configureTasks办法,然后设置使命内容和履行周期等,发动测验就完成了根据接口的守时使命,此时咱们改动数据库里的cron表达式也会实时收效

SpringBoot 中实现定时任务的几种方式

三、多线程守时使命

但上面的办法界说的守时使命会有个问题,就是假如我一个守时使命里边履行了复杂逻辑,导致自身履行花的时刻就现已超过了守时使命间隔的时刻怎么办呢?这时候守时使命的履行就会呈现必定的问题,具体如下,我用线程睡觉的办法模拟处理复杂逻辑

import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
@EnableScheduling //敞开守时使命
public class ScheduleTask {
    @Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
    public void testScheduleTask1() throws InterruptedException {
        System.out.println("履行守时使命1 " + LocalDateTime.now());
        Thread.sleep(10 * 1000);
    }
    @Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
    public void testScheduleTask2() {
        System.out.println("履行守时使命2 " + LocalDateTime.now());
    }
}

SpringBoot 中实现定时任务的几种方式

能够看到两个使命的履行时刻都被影响了,和咱们设置的5秒不对应。此时就能够使用多线程守时使命,对多线程的使用不了解的能够看我的另一篇文章 SpringBoot 中异步使命完成及自界说线程池履行异步使命

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 //敞开守时使命
@EnableAsync //敞开多线程
public class ScheduleTask {
    @Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
    @Async
    public void testScheduleTask1() throws InterruptedException {
        System.out.println("履行守时使命1 " + LocalDateTime.now());
        Thread.sleep(10 * 1000);
    }
    @Scheduled(cron = "0/5 * * * * ?") //守时使命注解+cron表达式
    @Async
    public void testScheduleTask2() {
        System.out.println("履行守时使命2 " + LocalDateTime.now());
    }
}

SpringBoot 中实现定时任务的几种方式

这样多线程的守时使命就完成了,每个守时使命之间不会相互影响,守时使命履行时刻太长也不会影响。

这就是守时使命完成的几种办法,对我们有协助的话多多点赞收藏哦,感谢!