美文网首页
SpringBoot 【 第三章 】定时管理

SpringBoot 【 第三章 】定时管理

作者: 陈兄 | 来源:发表于2019-01-25 13:56 被阅读0次
    image

    Schedule定时器

    定时任务想必是每个开发人员都必须要操作的。同步,异步方式密切的与业务相关。

    在Spring Boot启动类中加入@EnableScheduling注解,启用定时任务的配置

      /**
      * Created by cw on 2017/10/25. good day.
      *
      * @Author: Chen Wu
      * Blog: http://www.updatecg.xin
      */
      @EnableEurekaServer
      @SpringBootApplication
      @RestController
      @EnableScheduling
      @EnableConfigurationProperties
      public class EureKaServer extends SpringBootServletInitializer implements CommandLineRunner {
    
        public static void main(String[] args) {
            createLocalTempDirectory();
            SpringApplication.run(EureKaServer.class, args);
        }
      }
    

    定时任务类

      /**
      * Created by cw on 2017/10/25. good day.
      *
      * @Author: Chen Wu
      * Blog: http://www.updatecg.xin
      */
      @Component
      public class FileScheduled {
        private static Logger log = Logger.getLogger(FileScheduled.class);
        private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
    
        @Scheduled(cron = @Scheduled(cron="0 00 2 ? * *")
        private void deleteFile() {
            try {
                String path = String.join("/", System.getProperty("user.dir"), "tmp");
                FileUtil.cleanDir(path);
                log.info("Remove file success . data = " + dateFormat.format(new Date()));
            } catch (Exception e) {
                log.info("Remove file fail . data = " + dateFormat.format(new Date()));
                e.printStackTrace();
            }
        }
      }
    
    

    每天凌晨2点执行清除文件内容。

    @Scheduled详解

    SpringBoot @Scheduled 和spring相似。

    写法 含有
    @Scheduled(fixedRate = 60*1000) 固定每分钟执行一次
    @Scheduled(fixedDelay = 60*1000) 上次任务结束后一分钟后再次执行
    @Scheduled(cron=" 0 10,14,16 * * ?") 每天上午10点,下午2点,4点
    @Scheduled(cron=" 0/30 9-17 * * ?") 朝九晚五工作时间内每半小时
    @Scheduled(cron=" 0 12 ? * WED") 表示每个星期三中午12点
    @Scheduled(cron=" 0 12 * * ?") 每天中午12点触发
    @Scheduled(cron=" 15 10 ? * * ") 每天上午10:15触发
    @Scheduled(cron=" 15 10 * * ? ") 每天上午10:15触发
    @Scheduled(cron=" 15 10 * * ? * ") 每天上午10:15触发
    @Scheduled(cron=" 15 10 * * ? 2005") 2005年的每天上午10:15触发
    @Scheduled(cron=" * 14 * * ?") 在每天下午2点到下午2:59期间的每1分钟触发
    @Scheduled(cron=" 0/5 14 * * ?") 在每天下午2点到下午2:55期间的每5分钟触发
    @Scheduled(cron=" 0/5 14,18 * * ?") 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
    @Scheduled(cron=" 0-5 14 * * ?") 在每天下午2点到下午2:05期间的每1分钟触发
    @Scheduled(cron=" 10,44 14 ? 3 WED") 每年三月的星期三的下午2:10和2:44触发
    @Scheduled(cron=" 15 10 ? * MON-FRI") 周一至周五的上午10:15触发
    @Scheduled(cron=" 15 10 15 * ?") 每月15日上午10:15触发
    @Scheduled(cron=" 15 10 L * ?") 每月最后一日的上午10:15触发
    @Scheduled(cron=" 15 10 ? * 6L") 每月的最后一个星期五上午10:15触发
    @Scheduled(cron=" 15 10 ? * 6L 2002-2005") 2002年至2005年的每月的最后一个星期五上午10:15触发
    @Scheduled(cron=" 15 10 ? * 6#3") 每月的第三个星期五上午10:15触发

    同步调用

    定义Task类,创建三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10秒内)

      package com.androidmov.adManagement.maker.scheduled;
    
      import org.apache.log4j.Logger;
      import org.springframework.stereotype.Component;
    
      import java.util.Random;
    
      /**
      * Created by cw on 2017/10/27. good day.
      *
      * @Author: Chen Wu
      * Blog: http://www.updatecg.xin
      */
      @Component
      public class Task {
        private static Logger log = Logger.getLogger(Task.class);
        public static Random random =new Random();
    
        public void taskOne() throws InterruptedException {
            log.info("任务一开始执行...");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成任务一,耗时:" + (end - start) + "毫秒");
        }
    
        public void taskTwo() throws InterruptedException {
            log.info("任务二开始执行...");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成任务二,耗时:" + (end - start) + "毫秒");
        }
    
        public void taskThreee() throws InterruptedException {
            log.info("任务三开始执行...");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成任务一,耗时:" + (end - start) + "毫秒");
        }
      }
    

    容器启动调用此三个任务,执行结果是依次按照顺序执行。

      @Override
      public void run(String... strings) throws Exception {
        System.out.println("=========Application init============");
    
        task.taskOne();
        task.taskTwo();
        task.taskThreee();
      }
    

    执行结果:

      [No TaskScheduler/ScheduledExecutorService bean found for scheduled processing]
      [Tomcat started on port(s): 8093 (http)]
      [Updating port to 8093]
      =========Application init============
      [任务一开始执行...]
      [完成任务一,耗时:9821毫秒]
      [任务二开始执行...]
      [完成任务二,耗时:1043毫秒]
      [任务三开始执行...]
      [完成任务一,耗时:9580毫秒]
      [Started EureKaServer in 31.177 seconds (JVM running for 31.96)]
    

    结果显然按照任务一、任务二、任务三顺序的执行。

    异步调用/回调

    从上面可见同步调用是按照顺序来执行的,但是执行时间比较长。若这三个任务本身之间不存在依赖关系,可以并发执行的话,同步调用在执行效率方面就比较差,可以考虑通过异步调用的方式来并发执行。

    调用

    在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数。

      package com.androidmov.adManagement.maker.scheduled;
    
      import org.apache.log4j.Logger;
      import org.springframework.scheduling.annotation.Async;
      import org.springframework.stereotype.Component;
    
      import java.util.Random;
    
      /**
      * Created by cw on 2017/10/27. good day.
      *
      * @Author: Chen Wu
      * Blog: http://www.updatecg.xin
      */
      @Component
      public class AsynTask {
        private static Logger log = Logger.getLogger(AsynTask.class);
        public static Random random =new Random();
    
        @Async
        public void asynTaskOne() throws InterruptedException {
            log.info(" 任务一开始执行...");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成任务一,耗时:" + (end - start) + "毫秒");
        }
        @Async
        public void asynTaskTwo() throws InterruptedException {
            log.info(" 任务二开始执行...");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成任务二,耗时:" + (end - start) + "毫秒");
        }
        @Async
        public void asynTaskThreee() throws InterruptedException {
            log.info(" 任务三开始执行...");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成任务一,耗时:" + (end - start) + "毫秒");
        }
      }
    
    

    为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示:

      @EnableAsync
      public class EureKaServer extends SpringBootServletInitializer implements CommandLineRunner {
    
        @Autowired
        private SynTask task;
    
        public static void main(String[] args) {
            createLocalTempDirectory();
            SpringApplication.run(EureKaServer.class, args);
        }
        @Override
        public void run(String... strings) throws Exception {
            System.out.println("=========Application init============");
    
            task.taskOne();
            task.taskTwo();
            task.taskThreee();
        }
      }
    

    <strong>注: @Async所修饰的函数不要定义为static类型,这样异步调用不会生效.</strong>

    回调

    假设我们需要统计一下三个任务并发执行共耗时是多少。

    此时回调需要Future<T>来返回异步调用的结果。

      @Async
      public Future<String> taskOne() throws InterruptedException {
          log.info("任务一开始执行...");
          long start = System.currentTimeMillis();
          Thread.sleep(random.nextInt(10000));
          long end = System.currentTimeMillis();
          log.info("完成任务一,耗时:" + (end - start) + "毫秒");
          return new AsyncResult<>("任务一完成");
      }
    

    此时任务所消耗的时候明显比同步消耗的时间少。也不会去等待其他任务响应后再去执行。

      [Updating port to 8093]
      =========Application init============
      [No task executor bean found for async processing: no bean of type TaskExecutor and no bean named 'taskExecutor' either]
      [任务一开始执行...]
      [任务三开始执行...]
      [任务二开始执行...]
      [完成任务二,耗时:2540毫秒]
      [完成任务三,耗时:2684毫秒]
      [完成任务一,耗时:3486毫秒]
      [任务全部完成,总耗时:4015毫秒]
      [Started EureKaServer in 20.461 seconds (JVM running for 21.3)]
    

    <strong>对应代码分享在 [https://github.com/UpdateCw/SpringBoot]</strong>

    相关文章

      网友评论

          本文标题:SpringBoot 【 第三章 】定时管理

          本文链接:https://www.haomeiwen.com/subject/ijvmjqtx.html