摘要:本文介绍了Spring的定时任务。
环境
Windows 10 企业版 LTSC 21H2 Java 1.8 Maven 3.6.3 Spring 5.3.23
1 配置依赖 添加依赖:
pom.xml 1 2 3 4 5 6 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-context</artifactId > <version > 5.3.23</version > </dependency >
2 配置方式 2.1 编程式定时任务 编程式定时任务被封装成ScheduledFuture对象,不被Spring容器管理,Spring容器关闭时需要等待定时任务执行结束。
2.1.1 XML配置 创建任务类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class DemoTask { public void simpleTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行简单任务" ); } public void cronTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行克戎任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } public void fixedRateTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定速率任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } public void fixedDelayTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定延迟任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } }
创建配置文件:
spring.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" > <bean id ="demoTask" class ="com.example.task.DemoTask" /> <bean id ="taskScheduler" class ="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler" > <property name ="poolSize" value ="5" /> <property name ="threadNamePrefix" value ="scheduled-task-" /> <property name ="waitForTasksToCompleteOnShutdown" value ="true" /> <property name ="awaitTerminationSeconds" value ="60" /> </bean > </beans >
创建启动类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class DemoApplication { public static void main (String[] args) { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行主任务" ); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("spring.xml" ); DemoTask demoTask = context.getBean(DemoTask.class); ThreadPoolTaskScheduler taskScheduler = context.getBean(ThreadPoolTaskScheduler.class); taskScheduler.schedule(demoTask::simpleTask, new Date (System.currentTimeMillis() + 1000 )); taskScheduler.schedule(demoTask::cronTask, new CronTrigger ("0/2 * * * * ?" )); taskScheduler.scheduleAtFixedRate(demoTask::fixedRateTask, 2000 ); taskScheduler.scheduleWithFixedDelay(demoTask::fixedDelayTask, 2000 ); try { Thread.sleep(10000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } taskScheduler.shutdown(); System.out.println("取消定时任务" ); try { Thread.sleep(5000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } context.close(); } }
2.1.2 注解配置 修改任务类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 @Component public class DemoTask { public void simpleTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行简单任务" ); } public void cronTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行克戎任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } public void fixedRateTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定速率任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } public void fixedDelayTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定延迟任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } }
创建配置类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Configuration @ComponentScan("com.example") public class DemoConfig { @Bean public ThreadPoolTaskScheduler taskScheduler () { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler (); scheduler.setPoolSize(5 ); scheduler.setThreadNamePrefix("scheduled-task-" ); scheduler.setWaitForTasksToCompleteOnShutdown(true ); scheduler.setAwaitTerminationSeconds(60 ); scheduler.initialize(); return scheduler; } }
修改启动类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 public class DemoApplication { public static void main (String[] args) { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行主任务" ); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext (DemoConfig.class); DemoTask demoTask = context.getBean(DemoTask.class); ThreadPoolTaskScheduler taskScheduler = context.getBean(ThreadPoolTaskScheduler.class); taskScheduler.schedule(demoTask::simpleTask, new Date (System.currentTimeMillis() + 1000 )); taskScheduler.schedule(demoTask::cronTask, new CronTrigger ("0/2 * * * * ?" )); taskScheduler.scheduleAtFixedRate(demoTask::fixedRateTask, 2000 ); taskScheduler.scheduleWithFixedDelay(demoTask::fixedDelayTask, 2000 ); try { Thread.sleep(10000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } taskScheduler.shutdown(); System.out.println("取消定时任务" ); try { Thread.sleep(5000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } context.close(); } }
2.2 声明式定时任务 声明式定时任务被Spring容器管理,Spring容器关闭时不会等待定时任务执行结束。
2.2.1 XML配置 在spring.xml配置文件中启用任务调度,需要添加task命名空间。
创建任务类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class DemoTask { public void simpleTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行简单任务" ); } public void cronTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行克戎任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } public void fixedRateTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定速率任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } public void fixedDelayTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定延迟任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } }
创建配置文件:
spring.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:task ="http://www.springframework.org/schema/task" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd" > <bean id ="demoTask" class ="com.example.task.DemoTask" /> <task:scheduler id ="taskScheduler" pool-size ="5" /> <task:scheduled-tasks scheduler ="taskScheduler" > <task:scheduled ref ="demoTask" method ="cronTask" cron ="0/2 * * * * ?" /> <task:scheduled ref ="demoTask" method ="fixedRateTask" fixed-rate ="2000" /> <task:scheduled ref ="demoTask" method ="fixedDelayTask" fixed-delay ="2000" /> </task:scheduled-tasks > </beans >
创建启动类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class DemoApplication { public static void main (String[] args) { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行主任务" ); ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("spring.xml" ); ThreadPoolTaskScheduler taskScheduler = context.getBean(ThreadPoolTaskScheduler.class); try { Thread.sleep(10000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } taskScheduler.shutdown(); System.out.println("取消定时任务" ); try { Thread.sleep(5000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } context.close(); } }
2.2.2 半注解配置 在XML配置文件中使用task:annotation-driven标签启用任务调度注解,支持通过@Scheduled注解完成声明式定时任务的配置,代替在XML配置文件中配置定时任务。
使用@Scheduled注解管理定时任务,可以在方法上使用,这是声明式定时任务最常用的方式。
修改任务类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Component public class DemoTask { @Scheduled(cron = "0/2 * * * * ?") public void cronTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行克戎任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } @Scheduled(fixedRate = 2000) public void fixedRateTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定速率任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } @Scheduled(fixedDelay = 2000) public void fixedDelayTask () { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行固定延迟任务" ); try { Thread.sleep(3000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } } }
修改配置文件:
spring.xml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:context ="http://www.springframework.org/schema/context" xmlns:task ="http://www.springframework.org/schema/task" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd" > <context:component-scan base-package ="com.example" /> <bean id ="taskScheduler" class ="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler" > <property name ="poolSize" value ="5" /> <property name ="threadNamePrefix" value ="scheduled-task-" /> <property name ="waitForTasksToCompleteOnShutdown" value ="true" /> <property name ="awaitTerminationSeconds" value ="60" /> </bean > <task:annotation-driven scheduler ="taskScheduler" /> </beans >
2.2.3 全注解配置 使用@EnableScheduling注解启用任务调度注解,代替在XML配置文件中使用task:annotation-driven标签。
创建配置类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Configuration @EnableScheduling @ComponentScan("com.example") public class DemoConfig { @Bean public ThreadPoolTaskScheduler taskScheduler () { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler (); scheduler.setPoolSize(5 ); scheduler.setThreadNamePrefix("scheduled-task-" ); scheduler.setWaitForTasksToCompleteOnShutdown(true ); scheduler.setAwaitTerminationSeconds(60 ); scheduler.initialize(); return scheduler; } }
修改启动类:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class DemoApplication { public static void main (String[] args) { System.out.println(LocalDateTime.now() + " " + Thread.currentThread().getName() + " 执行主任务" ); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext (DemoConfig.class); ThreadPoolTaskScheduler taskScheduler = context.getBean(ThreadPoolTaskScheduler.class); try { Thread.sleep(10000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } taskScheduler.shutdown(); System.out.println("取消定时任务" ); try { Thread.sleep(5000 ); } catch (InterruptedException e) { throw new RuntimeException (e); } context.close(); } }
3 使用说明 定时任务使用TaskScheduler接口的ThreadPoolTaskScheduler主要实现类,它基于线程池提供了灵活的定时任务调度功能。
常用方法:
java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public ScheduledFuture<?> schedule(Runnable task, Date startTime);public ScheduledFuture<?> schedule(Runnable task, Trigger trigger);public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period);public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period);public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay);public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay);public void shutdown () ;
获取ScheduledFuture定时任务后支持关闭单个任务:
java 1 2 boolean cancel (boolean mayInterruptIfRunning) ;
4 克戎表达式 克戎表达式即Cron表达式,用于定义定时任务的执行规则。
克戎表达式由七个时间字段构成,顺序如下:
秒:取值范围在0-59之间,可使用, - * /特殊字符。
分:取值范围在0-59之间,可使用, - * /特殊字符。
时:取值范围在0-23之间,可使用, - * /特殊字符。
日:取值范围在1-31之间,可使用, - * ? /特殊字符。
月:取值范围在1-12之间,可使用, - * /特殊字符。
星期:取值范围在0-6之间,从星期日开始,可使用, - * ? /特殊字符。
年(可选):取值范围在1970-2099之间,可使用, - * /特殊字符。
特殊字符的含义:
*:表示任意值,例如*表示匹配字段的任意值。
,:表示枚举值,例如1,2,3表示匹配指定的多个值。
-:表示范围,例如1-3表示匹配范围内的连续值。
/:表示增量,例如0/5表示从0开始,每5分钟执行一次。
?:表示不指定值,只能用在日和星期中,当一个值为具体值时,另一个值必须为?避免冲突。
示例:
cron 1 2 3 4 5 0 0 8 * * ? - 每天8点执行 0 10 30 * * ? - 每天10:30执行 0 0/5 * * * ? - 每天每5分钟执行 0 0/5 12 * * ? - 每天12点到13点期间,每5分钟执行 0 0-5 12 * * ? - 每天12点到12:05期间,每1分钟执行
条