美文网首页
spring boot 中使用 cron任务

spring boot 中使用 cron任务

作者: 彩色代码 | 来源:发表于2020-07-21 12:55 被阅读0次

    第一种方式: spring boot 中引用

    main 函数引入:@EnableScheduling

    package org.test.springboot;
    
    import org.springframework.boot.*;
    import org.springframework.boot.autoconfigure.*;
    import org.springframework.scheduling.annotation.EnableScheduling;
    
    @SpringBootApplication
    @EnableScheduling
    public class Launcher {
        public static void main(String[] args) {
            SpringApplication.run(Launcher.class, args);
        }
    }
    
    
    package org.test.springboot.service;
    
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    @Service
    public class ScheduledService {
        @Scheduled(cron = "*/5 * * * * *")
        public void hello(){
            System.out.println("hello...");
        }
        @Scheduled(fixedRate = 5000)
        public void fixedRate(){
            System.out.println("fixedRate: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        }
    }
    
    1. fixedRate:定义一个按一定频率执行的定时任务

    2. fixedDelay:定义一个按一定频率执行的定时任务,与上面不同的是,该属性可以配合initialDelay, 定义该任务延迟执行时间。

    3. cron:通过表达式来配置任务执行时间

      @Scheduled中的参数说明

      `@Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行;` `@Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行;` `@Scheduled(initialDelay=1000, fixedDelay=2000):第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行;` `@Scheduled(cron=``"* * * * * ?"``):按cron规则执行。`
      

    延伸学习:

    可以看到2个定时任务都已经执行,并且使同一个线程中串行执行,如果只有一个定时任务,这样做肯定没问题,当定时任务增多,如果一个任务卡死,会导致其他任务也无法执行。

    多线程执行

    在传统的Spring项目中,我们可以在xml配置文件添加task的配置,而在SpringBoot项目中一般使用config配置类的方式添加配置,所以新建一个AsyncConfig类

    package org.test.springboot;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.Executor;
    
    @Configuration
    @EnableAsync
    public class AsyncConfig {
        /*
       此处成员变量应该使用@Value从配置中读取
        */
        private int corePoolSize = 10;
        private int maxPoolSize = 200;
        private int queueCapacity = 10;
        @Bean
        public Executor taskExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(corePoolSize);
            executor.setMaxPoolSize(maxPoolSize);
            executor.setQueueCapacity(queueCapacity);
            executor.initialize();
            return executor;
        }
    }
    

    @Configuration:表明该类是一个配置类
    @EnableAsync:开启异步事件的支持

    然后在定时任务的类或者方法上添加@Async 。最后重启项目,每一个任务都是在不同的线程中

    例如:

    package org.test.springboot.service;
    
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.Scheduled;
    import org.springframework.stereotype.Service;
    
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    @Service
    public class ScheduledService {
        @Async
        @Scheduled(cron = "*/5 * * * * *")
        public void hello(){
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("hello...");
        }
        @Async
        @Scheduled(fixedRate = 2000)
        public void fixedRate(){
            System.out.println("fixedRate: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        }
    }
    
    

    第二种方式 : 使用:Timer

    package org.test.springboot;
    
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class Launcher {
        public static void main(String[] args) {
            //SpringApplication.run(Launcher.class, args);
            TimerTask timerTask = new TimerTask() {
                @Override
                public void run() {
                    System.out.println("task  run:"+ new Date());
                }
            };
            Timer timer = new Timer();
            //安排指定的任务在指定的时间开始进行重复的固定延迟执行。这里是每3秒执行一次
            timer.schedule(timerTask,10,3000);
        }
    }
    

    第三种方法:使用ScheduledExecutorService

    package org.test.springboot;
    
            import java.util.Date;
            import java.util.concurrent.Executors;
            import java.util.concurrent.ScheduledExecutorService;
            import java.util.concurrent.TimeUnit;
    
    public class Launcher {
        public static void main(String[] args) {
            ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
            // 参数:1、任务体
            //      2、首次执行的延时时间
            //      3、任务执行间隔
            //      4、间隔时间单位
            service.scheduleAtFixedRate(()->System.out.println("task ScheduledExecutorService "+new Date()), 0, 3, TimeUnit.SECONDS);
        }
    }
    
    

    cron表达式

    注:下面内容主要参考Quartz的文档,对于Spring Task基本都适用。
    
    cron表达式是由7个域组成的字符串,它们描述了任务计划的各个细节,这些域用空格分隔,每个域代表的含义如下:
    
    Seconds(秒)
    Minutes(分)
    Hours(时)
    Day-of-Month(日)
    Month(月)
    Day-of-Week(星期)
    Year(可选字段)(年)
    示例:0 0 10 ? * WED表示每个星期三的10:00:00
    
    表达式 {秒} {分} {时} {日} {月} {周} {年}(可选)
    允许值 0~59    0~59    0~23    1~31    1~12
    JAN~DEC 1~7
    SUN~SAT 1970~2099
    特殊值 , - * / , - * / , - * / , - * /
    ? L W C , - * / , - * /
    ? L C # , - * /
    说明:下面描述中,XX域则表示cron表达式相应的位置,如秒域表示cron中第1个值,日域则表示cron表达式第4个值等等。
    
    月份简称:JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV和DEC。
    星期简称:SUN,MON,TUE,WED,THU,FRI和SAT。其中,1表示SUN。
    ,:用来分割在域上指定的多个值。如:MON,WED,FRI在星期域里表示星期一、星期三、星期五。
    /:用于指定增量值。如分钟上使用0/15,表示从零开始,每隔15分钟,等价于0,15,30,45。如分钟上使用3/15,表示从第3分钟开始,每隔15分钟,等价于3,18,33,48,x/y中x表示开始值,y表示步长。
    *:表示匹配该域的任意值。如秒上使用*表示每秒触发一次。
    -:表示指定一个范围,如分钟域上10-13,表示10分、11分、12分、13分。
    ?:表示不关心的域,可用于日和周两个域上,主要用来解决日和周两个域的冲突。和*类似,区别在于*关心域,只是域的值可以任意,?则表示对该域不关心,不需要看该域的内容,直接忽略。
    L:表示最后,是单词last的首字母,可用于日和周两个域上,用在日和周上含义不同: 
    日域上表示月份中日期的最后一天,如一月的第31天、非闰年二月的第28天。
    周域上单独使用仅表示7或SAT,即仅表示周六。但是如果跟在其他值后,如6L或FRIL则表示该月中最后一个星期五。
    L还可以指定偏移量,如日域指定L-3,表示该月倒数第3天。当使用L时其值尽量不要指定列表或范围,以免令人困惑。
    W:用于日域,表示距离指定日最近的星期几(周一至周五中的一个),如:日域上值为15W则表示距离本月第15日最近的工作日。
    
    # :用于周域,表示该月的第n个星期几。如:周域值为6#3或FRI#3表示该月的第3个星期五。
    
    四、常用表达式示例
    0 0 10,14,16 * * ?每天上午10点、下午两点、下午4点整触发
    0 0/30 9-17 * * ? 每天朝九晚五内每隔半小时触发
    0 15 10 ? * MON-FRI 周一至周五的上午10:15触发
    0 0/5 * * * ?每5分钟触发
    10 0/5 * * * ?每隔5分钟的第10秒触发(即10:00:10、10:05:10、10:10:10等)
    30 * * * * ? 每半分钟触发
    30 10 * * * ? 每小时的10分30秒触发
    30 10 1 * * ? 每天1点10分30秒触发
    30 10 1 20 * ? 每月20号1点10分30秒触发
    30 10 1 20 10 ? * 每年10月20号1点10分30秒触发
    30 10 1 20 10 ? 2011 2011年10月20号1点10分30秒触发
    30 10 1 ? 10 * 2011 2011年10月每天1点10分30秒触发
    30 10 1 ? 10 SUN 2011 2011年10月每周日1点10分30秒触发
    15,30,45 * * * * ? 每15秒,30秒,45秒时触发
    15-45 * * * * ? 15到45秒内,每秒都触发
    15/5 * * * * ? 每分钟的每15秒开始触发,每隔5秒触发一次
    15-30/5 * * * * ? 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次
    0 0/3 * * * ? 每小时的第0分0秒开始,每三分钟触发一次
    0 15 10 ? * MON-FRI 星期一到星期五的10点15分0秒触发
    0 15 10 L * ? 每个月最后一天的10点15分0秒触发
    0 15 10 LW * ? 每个月最后一个工作日的10点15分0秒触发
    0 15 10 ? * 5L 每个月最后一个星期四的10点15分0秒触发
    
    0 15 10 ? * 5#3 每个月第三周的星期四的10点15分0秒触发
    

    相关文章

      网友评论

          本文标题:spring boot 中使用 cron任务

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