SpringBoot——使用@Scheduled定时器
@Scheduled注解是 Spring Boot 提供的定时任务配置工具,用于控制任务执行时间。
使用方法:
- 先启用定时器配置,添加注解@EnableScheduling,可在@SpringBootApplication或者@Configuration或者@Component等spring能够扫描到的地方;
- 在spring能够识别的类中定义没有返回值和参数的方法,在方法上使用@Scheduled注解;
@Scheduled注解的参数解释:
- fixedRate:固定速率(ms),按照每次任务的开始时间间隔执行(定时器启动的时候每次开始时间就已确定),上一次任务执行时间超过后面的任务开始时间,后面任务会积压到队列里,等这个时间很长的任务结束后,队列里的积压任务全部同时放行;
- fixedRateString:同上,字符串类型,支持${}占位符,可灵活配置;
- fixedDelay:固定延迟(ms),以上次的结束时间开始延迟一定时间执行下一次,不会积压;
- fixedDelayString:同上,字符串类型,支持${}占位符,可灵活配置;
- initialDelay:延迟启动定时器时间(ms),指定一段时间后才开始启动定时器;
- initialDelayString:同上,字符串类型,支持${}占位符,可灵活配置;
- cron:cron表达式,比上面的更灵活,字符串类型,支持${}占位符,上次任务如果超时会自动丢弃当前时间应该执行的任务;(跟linux的cron稍有区别,linux的是“分时日月周”,这个是“秒分时日月周[年]”,多了秒和可省略的年)
- zone:时区,一般默认即可,自动使用服务器时区,也可指定如“Asia/Shanghai”;
PS:占位符可以只占String的一部分;定时器里如果抛出异常不会影响下一次任务;对cron的简单理解,可以把每个字段的设置都解释为一个整数数组,例如在秒字段上的0/10,可以解释成[0, 10, 20, 30, 40, 50],在月字段上的*表示所有值,可解释成[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],也就是每个月都有;
测试代码:
启动类:
package testspringschedule;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class TestSpringSchedule {public static void main(String[] args) {System.out.println("main start");SpringApplication.run(TestSpringSchedule.class, args);}}
测试fixedRate:
package testspringschedule;import java.util.Date;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;//@Configuration
@Component
//@EnableScheduling
public class MyRateSchedule {@Scheduled(fixedRate = 5000, initialDelay = 3000, zone = "Asia/Shanghai")
// @Scheduled(fixedRateString = "5000", initialDelayString = "3000")
// @Scheduled(fixedRateString = "${abc:5}000", initialDelayString = "${def:3000}")public void test1() {System.out.println("fixedRate start:" + new Date());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("fixedRate stop:" + new Date());}private int i = 0;
// @Scheduled(fixedRate = 1000, initialDelay = 3000)public void test2() {System.out.println("fixedRate start:" + new Date());i++;System.out.println(i);if (i == 5) {try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("fixedRate stop:" + new Date());}}
test1()执行结果,开始时间都是间隔5s:
test2()执行结果,开始时间间隔1s,超时积压多个任务等上一个任务结束后全部同时执行;
测试fixedDelay:
package testspringschedule;import java.util.Date;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class MyDelaySchedule {@Scheduled(fixedDelay = 5000, initialDelay = 3000)public void test1() {System.out.println("fixedDelay start:" + new Date());try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("fixedDelay stop:" + new Date());}}
执行结果:
测试cron:
package testspringschedule;import java.util.Date;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class MyCronSchedule {@Scheduled(cron = "50/2 * * * * ?")
// @Scheduled(cron = "${s:1/2 * * * * ?}")
// @Scheduled(cron = "${s:0/5} * * * * ?")public void test1() {System.out.println("cron:" + new Date());}// @Scheduled(cron = "0/10 * * * * ?")public void test2() {System.out.println("cron start:" + new Date());try {Thread.sleep(11000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("cron stop:" + new Date());}}
test1()执行结果:
test2()执行结果,超时丢弃:
也可以实现SchedulingConfigurer接口,使用配置类进行线程池、异常处理、拒绝策略等的一些配置:
package testspringschedule;import java.util.concurrent.ThreadPoolExecutor;import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.util.ErrorHandler;@Configuration
public class MyScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {final ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();taskScheduler.setPoolSize(50);taskScheduler.setThreadGroupName("Scheduled-Group");taskScheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());taskScheduler.setErrorHandler(new ErrorHandler() {@Overridepublic void handleError(Throwable t) {System.out.println("发生未捕获异常:");t.printStackTrace();}});taskScheduler.initialize();taskRegistrar.setTaskScheduler(taskScheduler);}}