SpirngBoot - 定时任务入门(@Scheduled )详解

项目开发中经常需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息。Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor 、TaskScheduler 接口。

SpringBoot中使用两个注解:@EnableScheduling、@Scheduled来简单实现定时任务。


【1】@Scheduled注解

按照惯例,先看javadoc源码:

使一个方法定时被执行的注解。其属性cron/fixedDelay/fixedRate必须有一个被指定

该注解标记的方法没有参数,也没有返回值。即使写了返回值,也会被忽略。
 
该注解被ScheduledAnnotationBeanPostProcessor处理器解析。

可以手动注册该bean,当然更方便的是使用配置或者@EnableScheduling注解。
 
这个注解可以用来作为一个meta-annotation通过属性覆盖去创建自定义的组合注解。
 
 * @see EnableScheduling
 * @see ScheduledAnnotationBeanPostProcessor
 * @see Schedules
 */
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {

	 cron表达式
	 * @return an expression that can be parsed to a cron schedule
	 * @see org.springframework.scheduling.support.CronSequenceGenerator
	 */
	String cron() default "";

	 corn表达式的时区,默认为空,使用服务器的local time zone。
	 * @return a zone id accepted by {@link java.util.TimeZone#getTimeZone(String)},
	 * or an empty String to indicate the server's default time zone
	 * @since 4.0
	 * @see org.springframework.scheduling.support.CronTrigger#CronTrigger(String, java.util.TimeZone)
	 * @see java.util.TimeZone
	String zone() default "";

	  周期为在最后一次调用结束和下一次调用开始,以毫秒为单位,
	  固定周期地执行注释的方法。
	long fixedDelay() default -1;

	  周期间隔为在最后一次调用结束和下一次调用开始,以毫秒为单位,
	  固定周期地执行注释的方法。
	String fixedDelayString() default "";

	固定周期地执行注解方法,周期为调用间隔,单位为毫秒
	long fixedRate() default -1;
	String fixedRateString() default "";

	
	 fixedRate() 或fixedDelay()第一次执行前延迟的毫秒数
	long initialDelay() default -1;

	 fixedRate() 或fixedDelay()第一次执行前延迟的毫秒数
	String initialDelayString() default "";

}

【2】@EnableScheduling 注解

启动Spring的定时任务执行能力,通常用在配置类上面,类似于xml片段。

配置类中使用方法如下:
 * @Configuration
 * @EnableScheduling
 * public class AppConfig {
 *     // various @Bean definitions
 * }
 该注解会使Spring 容器中所有bean中的@Scheduled注解起作用。
-------------------------------------------第一种使用方式-------------------------------------------
如下所示,给定一个类MyTask :

 * package com.myco.tasks;

 * public class MyTask {
 *// 每1000ms 执行一次该方法
 *     @Scheduled(fixedRate=1000)
 *     public void work() {
 *         // task execution logic
 *     }
 * }
 如下配置确保MyTask.work()每1000ms被调用一次。
 * @Configuration
 * @EnableScheduling
 * public class AppConfig {
 *
 *     @Bean
 *     public MyTask task() {
 *         return new MyTask();
 *     }
 * }
 *
-------------------------------------------第二种使用方式-------------------------------------------
如果MyTask使用了注解@Component,下面的配置将会确保其@Scheduled标注的方法会被以期望的间隔进行调用。
 * @Configuration
 * @EnableScheduling
 * @ComponentScan(basePackages="com.myco.tasks")
 * public class AppConfig {
 * }
-------------------------------------------第三种使用方式------------------------------------------- *// 甚至可以直接在配置类中写@Scheduled注解标注的方法。 * @Configuration * @EnableScheduling * public class AppConfig { * * @Scheduled(fixedRate=1000) * public void work() { * // task execution logic * } * } * 默认,将会寻找一个相关联的scheduler ,可能是上下文中一个唯一的TaskScheduler或者一个bean id为taskScheduler * ScheduledExecutorService也将执行同样的查找。 * 如果上面两个定时任务处理器都没有被找到,一个本地单线程默认scheduler 将会被创建并被注册器使用。 如果想获得更多的控制,配置类应该实现SchedulingConfigurer接口。 这将可以获取底层的ScheduledTaskRegistrar实例。 下面的例子演示了如何自定义Executor去执行定时任务。 * @Configuration * @EnableScheduling * public class AppConfig implements SchedulingConfigurer { * * @Override * public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { * taskRegistrar.setScheduler(taskExecutor()); * } * * @Bean(destroyMethod="shutdown") * public Executor taskExecutor() { * return Executors.newScheduledThreadPool(100); * } * } 注意上面例子中@Bean(destroyMethod="shutdown")的使用。 这将确保线程任务执行器在Spring容器被销毁时正确的关闭。 实现SchedulingConfigurer还可以通过ScheduledTaskRegistrar对任务注册实细粒度的控制。 * 例如,以下为每个自定义{@code Trigger}实现配置特定bean方法的执行 * @Configuration * @EnableScheduling * public class AppConfig implements SchedulingConfigurer { * * @Override * public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { * taskRegistrar.setScheduler(taskScheduler()); * taskRegistrar.addTriggerTask( * new Runnable() { * public void run() { * myTask().work(); * } * }, * new CustomTrigger() * ); * } * * @Bean(destroyMethod="shutdown") * public Executor taskScheduler() { * return Executors.newScheduledThreadPool(42); * } * * @Bean * public MyTask myTask() { * return new MyTask(); * } * } * 作为参考,可以将上面的示例与下面的Spring XML配置进行比较 * * * * * * * * * * * * * * The examples are equivalent save that in XML a fixed-rate period is used * instead of a custom {@code Trigger} implementation; this is because the * {@code task:} namespace {@code scheduled} cannot easily expose such support. This is * but one demonstration how the code-based approach allows for maximum configurability * through direct access to actual componentry.

* * @see Scheduled * @see SchedulingConfiguration * @see SchedulingConfigurer * @see ScheduledTaskRegistrar * @see Trigger * @see ScheduledAnnotationBeanPostProcessor */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documented public @interface EnableScheduling { }


【3】代码实例

Service如下(这里使用cron表达式):

@Service
public class ScheduledService {
	// 每天的整分调用一次该方法
    @Scheduled(cron = "0 * * * * 0-7")
    public void hello(){
        System.out.println("hello...");
    }
}

在主程序上添加@EnableScheduling注解如下:

@SpringBootApplication
@EnableScheduling
public class SpringBoot01CacheApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBoot01CacheApplication.class, args);
	}
}

SpirngBoot - 定时任务入门(@Scheduled )详解_第1张图片


fixedRate ,fixedDelay 和initialDelay

代码示例如下:

	//上一次 项目启动时间点之后 5 秒执行一次
    @Scheduled(fixedRate = 5000)
    public void fixedRate(){
        System.out.println("fixedRate: " + new SimpleDateFormat("HH:mm:ss").format(new Date()));
    }
	//上一次 结束时间点之后 每50秒执行一次
    @Scheduled(fixedDelay = 50000)
    public void fixedDelay(){
        for (int i = 0; i < 10; i++){
            System.out.println("fixedDelay" + i  + new SimpleDateFormat("HH:mm:ss").format(new Date()));
        }
    }
    // initialDelay :fixedRate() 或fixedDelay()第一次执行前延迟的毫秒数
	//第一次延迟50秒执行,之后按照fixedRate的规则每6秒执行一次
    @Scheduled(initialDelay = 50000,fixedRate = 6000)
    public void initialDelayFixedRate (){
        for (int i = 0; i < 10; i++){
            System.out.println("initialDelayFixedRate :" + i + new SimpleDateFormat("HH:mm:ss").format(new Date()) );
        }
    }

【4】cron表达式

cron表达式属性如下:

second(秒), minute(分), hour(时),day of month(日),month(月),day of week(周几)

字段与值表格如下:

字段 允许值 允许的特殊符号
0-59 ,-*/
0-59 ,-*/
小时 0-23 ,-*/
日期 1-31 ,-*?/LWC
月份 1-12 ,-*/
星期 0-7或SUN-SAT 0 7是SUN ,-*?/LC#

特殊符号释义如下:

特殊符号 代表含义
, 枚举
- 区间
* 任意
/ 步长
? 日/星期冲突匹配
L 最后
W 工作日
C 和Calendar联系后计算过的值
# 星期 4#2 第2个星期四

示例如下:

0 0 0 * * * -- 每天零时执行一次
0 0/15 14,18 * * ? -- 每天14点整和18点整,每隔15分钟执行一次
0 15 10 ? * 1-6 -- 每个月的周一到周六 10:15分执行一次
0 0 2 ? * 6L -- 每个月的最后一个周六凌晨2点执行一次
0 0 2 LW * ? -- 每个月的最后一个工作日凌晨2点执行一次
0 0 2-4 ? * 1#1 -- 每个月的第一个周一凌晨2点到4点期间,每个整点都执行一次

实现定时任务的方式很多,其他的有JDK 自带的 TimerTask or Timer、使用开源作业调度框架 Quartz、线程池 ScheduleExecutorService 和其实现类ScheduledThreadPoolExecutor。

参考博文:多线程并发之Executor。

你可能感兴趣的:(SpringBoot)