spring boot 中使用 cron任务

2020-07-21  本文已影响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秒触发
上一篇下一篇

猜你喜欢

热点阅读