zoukankan      html  css  js  c++  java
  • spring boot 系列之八:SpringBoot处理定时任务

    项目经常会用到定时任务,springboot自然是可以通过整合相关组件来实现的。

    目前常用的定时任务的实现有两种:

    1. 通过spring 自带的定时器任务@Schedule来实现
    2. 通过Quartz来实现

    本次借用上一篇《spring boot 整合Mybatis》的既有项目结构进行案例调试。

    一、cron表达式

    无论上面说的哪种实现方式,都需要用到cron表达式,因此不得不先介绍下它。

    Cron表达式是一个字符串,由6或7个域组成,每个域有不同的含义,每个域之间用空格隔开。有2中格式:

    Seconds Minutes Hours DayofMonth Month DayofWeek Year (7个域)
    Seconds Minutes Hours DayofMonth Month DayofWeek (6个域)

    每个域可能出现的值:

    Seconds:有效范围为0-59的整数
    Minutes:有效范围为0-59的整数
    Hours:有效范围为0-23的整数
    DayofMonth:有效范围为0-31的整数
    Month:有效范围为1-12的整数或JAN-DEC
    DayofWeek:有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一, 依次类推
    Year:有效范围为1970-2099年
    

    除了以上内容外,还可能出现一些特殊字符:

    (1)*:表示匹配该域的任意值,假如在Minutes域使用*, 即表示每分钟都会触发事件。
    
    (2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的10日触发调度,不管10日到底是星期几,则只能使用如下写法: 13 13 15 10 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。 
    
    (3)-:表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次 
    
    (4)/:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次. 
    
    (5),:表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。 
    
    (6)L:表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。 
    
    (7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 
    
    (8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。 
    
    (9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
    

    举例:

    @Scheduled(cron = “0 0 1 1 1 ?”)//每年一月的一号的 1:00:00 执行一次

    @Scheduled(cron = “0 0 1 1 1,6 ?”) //一月和六月的一号的 1:00:00 执行一次

    @Scheduled(cron = “0 0 1 1 1,4,7,10 ?”) //每个季度的第一个月的一号的 1:00:00 执行一次

    @Scheduled(cron = “0 0 1 1 * ?”)//每月一号 1:00:00 执行一次

    @Scheduled(cron=“0 0 1 * * *”) //每天凌晨 1 点执行一次

    以上看上去有点复杂,不过不用担心,记住常用的就行了。另外,现在网上还有 在线Cron表达式生成器可以帮助我们设定确定相关表达式内容。

    二、@Schedule实现

    1.引入依赖

    <!--添加schedule依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
    </dependency>
    

    2.代码实现

    1. 新建类JdkSchedule

      @Component
      public class JdkSchedule {
      
          @Autowired
          UserService userService;
      
          @Scheduled(cron = "0/2 * * * * ?") //每个两秒触发一次
          public void scheduleGetUserList() {
              System.out.println("**触发JDK 定时器***");
              List<User> list = userService.getUserList(new User());
              for (User user :list ){
                  System.out.println(user.toString());
              }
          }
      }
      

      里面的userService为上一次添加的内容

    2. 启动类添加注解,启动定时任务

      @EnableScheduling
      

    3.测试效果

    每隔两秒打印一次:

    **触发JDK 定时器***
    User{id=1, name='sam', age=32}
    User{id=2, name='hah ', age=10}
    

    三、Quartz实现

    1.Quartz介绍

    Quartz是一个完全由Java编写的开源任务调度的框架,通过触发器设置作业定时运行规则,控制作业的运行时间。它包括调度器、触发器、作业。

    组成 描述
    Job--任务 做什么事?
    Trigger--触发器 什么时候做?
    Scheduler--调度器 什么时候需要去做什么事情?

    2.基本使用

    • 引入依赖

      <!--引入quartz依赖-->
      <dependency>
          <groupId>org.quartz-scheduler</groupId>
          <artifactId>quartz</artifactId>
      </dependency>
      
    • 创建job类

      public class MyJob implements Job {
          @Override
          public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
              System.out.println("...quartz job 触发执行...");
          }
      }
      

      需要实现Quartz的Job接口

    • 编写测试类:

      /**
       * quartz原生态用法
       */
      public class JobTestMain {
          public static void main(String[] args) throws SchedulerException {
              //1.创建job
              JobDetail job = JobBuilder.newJob(MyJob.class).build();
      
              //2.创建trigger
              CronTrigger trigger = TriggerBuilder.newTrigger()
                      .withSchedule(CronScheduleBuilder.cronSchedule("0/3 * * * * ?"))
                      .build();
      
              //3.创建schedule
              Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
              scheduler.scheduleJob(job, trigger);
              scheduler.start();
          }
      }
      
    • 执行测试类JobTestMain:

      每三秒打印一次:

      ...quartz job 触发执行...

    3.springboot整合使用

    • 引入依赖

      <!--添加schedule依赖-->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context-support</artifactId>
      </dependency>
      
      <!--引入quartz依赖-->
      <dependency>
          <groupId>org.quartz-scheduler</groupId>
          <artifactId>quartz</artifactId>
      </dependency>
      <!--引入spring tx依赖-->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-tx</artifactId>
      </dependency>
      

      springboot整合的时候,需要添加这三个依赖。

    • 编写配置类

      /**
       * springboot整合quartz使用方法
       */
      @Configuration
      public class QuartzConfig {
      
          /**
           * 创建job对象
           * @return
           */
          @Bean
          public JobDetailFactoryBean jobDetailFactoryBean() {
              JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
              jobDetailFactoryBean.setJobClass(MyJob.class);
              return jobDetailFactoryBean;
          }
      
          /**
           * 创建trigger对象 - cron表达式对象
           * @param jobDetailFactoryBean
           * @return
           */
          @Bean
          public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
              CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
              cronTriggerFactoryBean.setCronExpression("0/5 * * * * ?");
              // 关联JobDetail对象
              cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
              return cronTriggerFactoryBean;
          }
      
          /**
           * 创建trigger对象 - 一般对象
           * @param jobDetailFactoryBean
           * @return
           */
          @Bean
          public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
              SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
              // 关联JobDetail对象
              simpleTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
              // 设置重复次数,这里配置的是重复次数,而不是总次数; 总次数=重复次数+1,也就是说这里配置的次数是:执行完一次之后,再重复执行的次数
              simpleTriggerFactoryBean.setRepeatCount(1);
              // 设置间隔时间
              simpleTriggerFactoryBean.setRepeatInterval(2000);
              return simpleTriggerFactoryBean;
          }
      
          /**
           * 创建schedule对象
           * @param triggerFactoryBean
           * @return
           */
          @Bean
          public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean triggerFactoryBean){
              SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
              schedulerFactoryBean.setTriggers(triggerFactoryBean.getObject());
              return schedulerFactoryBean;
          }
      }
      

      这里需要注意下,schedulerFactoryBean()方法中传入的参数如果是CronTriggerFactoryBean,则执行的是cronTriggerFactoryBean()对应的设置;参数如果是SimpleTriggerFactoryBean,则执行的是simpleTriggerFactoryBean()对应的设置。

    • 启动类添加注解

      @EnableScheduling

    • 测试效果

      每5秒钟执行一次:

      ...quartz job 触发执行...

      如果前面的@Schedule和这里的Quartz的定时任务放在一起了,则执行效果为两个Job一起执行:

      ...quartz job 触发执行...
      User{id=1, name='sam', age=32}
      User{id=2, name='hah ', age=10}
      **触发JDK 定时器***
      User{id=1, name='sam', age=32}
      User{id=2, name='hah ', age=10}
      **触发JDK 定时器***
      User{id=1, name='sam', age=32}
      User{id=2, name='hah ', age=10}
      **触发JDK 定时器***
      ...quartz job 触发执行...
      User{id=1, name='sam', age=32}
      User{id=2, name='hah ', age=10}
      **触发JDK 定时器***
      User{id=1, name='sam', age=32}
      User{id=2, name='hah ', age=10}
      **触发JDK 定时器***
      User{id=1, name='sam', age=32}
      User{id=2, name='hah ', age=10}
      ...quartz job 触发执行...
      

    以上即为本文全部内容。

    本文来自博客园,作者:JAVA开发老菜鸟,转载请注明原文链接:https://www.cnblogs.com/sam-uncle/p/15238215.html

  • 相关阅读:
    Working with WordprocessingML documents (Open XML SDK)
    How to Choose the Best Way to Pass Multiple Models in ASP.NET MVC
    Azure:Manage anonymous read access to containers and blobs
    Convert HTML to PDF with New Plugin
    location.replace() keeps the history under control
    On the nightmare that is JSON Dates. Plus, JSON.NET and ASP.NET Web API
    HTTP Modules versus ASP.NET MVC Action Filters
    解读ASP.NET 5 & MVC6系列(6):Middleware详解
    Content Negotiation in ASP.NET Web API
    Action Results in Web API 2
  • 原文地址:https://www.cnblogs.com/sam-uncle/p/15238215.html
Copyright © 2011-2022 走看看