zoukankan      html  css  js  c++  java
  • SpringBoot中的定时任务

    一、基于注解(@Scheduled)

    • 基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。

    1. 创建定时器

    • 使用SpringBoot基于注解来创建定时任务非常简单,只需几行代码便可完成。 代码如下:
      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. 代表当前类是一个配置类
      @EnableScheduling // 2.开启定时任务
      public class StaticScheduleTask {
          //3.添加定时任务
          @Scheduled(cron = "0/5 * * * * ?")
          //或直接指定时间间隔,例如:5秒
          //@Scheduled(fixedRate=5000)
          private void configureTask() {
              System.out.println("执行静态定时任务时间" + LocalDateTime.now());
          }
      }
      
      image

    1.2 Cron表达式参数分别表示:

    1. 秒(0~59) 例如0/5表示每5秒
    2. 分(0~59)
    3. 时(0~23)
    4. 日(0~31)的某天,需计算
    5. 月(0~11)
    6. 周几( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)
    • @Scheduled:除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。
      # Cron表达式范例:
      每隔5秒执行一次:*/5 * * * * ?
      每隔1分钟执行一次:0 */1 * * * ?
      每天23点执行一次:0 0 23 * * ?
      每天凌晨1点执行一次:0 0 1 * * ?
      每月1号凌晨1点执行一次:0 0 1 1 * ?
      每月最后一天23点执行一次:0 0 23 L * ?
      每周星期天凌晨1点实行一次:0 0 1 ? * L
      在26分、29分、33分执行一次:0 26,29,33 * * * ?
      每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
      
    • 更详细的 cron参数
      https://blog.csdn.net/Qiwan2/article/details/89848298
      https://blog.csdn.net/weixin_30720461/article/details/91388486

    二、基于接口(SchedulingConfigurer)

    • 从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就派上用场了。
    • 基于接口(SchedulingConfigurer)

    2.1 依赖

        <!--web启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--添加MySql依赖 -->
        <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>
        <!--添加Mybatis依赖 配置mybatis的一些初始化的东西-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
    

    2.2 创建数据库

    • 开启本地数据库mysql,随便打开查询窗口,然后执行脚本内容,如下:
    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 * * * * ?');
    
    # 连接参数配置
    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 创建定时器

    • 数据库准备好数据之后,我们编写定时任务,注意这里添加的是TriggerTask,目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。
    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. 主要用于标记配置类,兼备 Component的效果
    @EnableScheduling //2. 开启定时任务
    public class DynamicScheduleTask implements SchedulingConfigurer {
        @Mapper
        public interface CronMapper {
            @Select("select cron from cron limit 1")
            public String getCron();
        }
    
        @Resource
        CronMapper cronMapper;
    
        /**
         * 执行定时任务
         *
         * @param scheduledTaskRegistrar
         */
        @Override
        public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
            scheduledTaskRegistrar.addTriggerTask(
                    //1. 添加任务内容(Runnable)
                    () -> System.out.println("动态定时任务:" + LocalDateTime.now().toLocalTime()),
                    //2. 设置执行周期(Trigger)
                    triggerContext -> {
                        //2.1 从数据库获取执行周期
                        String cron = cronMapper.getCron();
                        //2.2 合法性校验
                        if (StringUtils.isEmpty(cron)) {
                            // Omitted Code ...
                        }
                        //2.3 返回执行周期(Date)
                        return new CronTrigger(cron).nextExecutionTime(triggerContext);
                    });
        }
    }
    

    2.4 启动测试

    • 启动应用后,查看控制台,打印时间是我们预期的每5秒一次:
    • 注意: 如果在数据库修改时格式出现错误,则定时任务会停止,即重新修改正确;此时只能重新启动项目才能恢复。
      image

    三、基于注解设定多线程定时任务

    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 //@Component注解用于对那些比较中立的类进行注释
    @EnableScheduling //1. 开启定时任务
    @EnableAsync //2. 开启多线程
    public class MultithreadScheduleTask {
    
        @Async//3. @Async就可以定义一个线程任务
        @Scheduled(fixedDelay = 1000)
        public void first() throws InterruptedException {
            System.out.println("第一个定时任务开始" + LocalDateTime.now().toLocalTime());
            Thread.sleep(1000 * 10);
        }
    
        @Async
        @Scheduled(fixedDelay = 1000)
        public void second() throws InterruptedException {
            System.out.println("第二个定时任务开始" + LocalDateTime.now().toLocalTime());
            System.out.println();
        }
    
    }
    

    image

    • 从控制台可以看出,第一个定时任务和第二个定时任务互不影响;
      并且,由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。

    参考

  • 相关阅读:
    tomcat内存溢出问题解决
    redis知识点汇总
    activiti全部知识点
    Python_Note_Preview_03_URL
    S&P_09_协方差(协方差矩阵)与相关系数
    Linear_algebra_06_ 内积空间
    Linear_algebra_05_线性方程组的解理论
    Linear_algebra_04_向量空间
    Linear_algebra_03_矩阵
    Linear_algebra_02_行列式
  • 原文地址:https://www.cnblogs.com/zk2020/p/15790212.html
Copyright © 2011-2022 走看看