|
| 1 | +很多时候我们都需要为系统建立一个定时任务来帮我们做一些事情,SpringBoot 已经帮我们实现好了一个,我们只需要直接使用即可,当然你也可以不用 SpringBoot 自带的定时任务,整合 Quartz 很多时候也是一个不错的选择。 |
| 2 | + |
| 3 | +本文不涉及 SpringBoot 整合 Quartz 的内容,只演示了如何使用 SpringBoot 自带的实现定时任务的方式。 |
| 4 | + |
| 5 | +## Spring Schedule 实现定时任务 |
| 6 | + |
| 7 | +我们只需要 SpringBoot 项目最基本的依赖即可,所以这里就不贴配置文件了。 |
| 8 | + |
| 9 | +### 1. 创建一个 scheduled task |
| 10 | + |
| 11 | +我们使用 `@Scheduled` 注解就能很方便地创建一个定时任务,下面的代码中涵盖了 `@Scheduled `的常见用法,包括:固定速率执行、固定延迟执行、初始延迟执行、使用 Cron 表达式执行定时任务。 |
| 12 | + |
| 13 | +> Cron 表达式: 主要用于定时作业(定时任务)系统定义执行时间或执行频率的表达式,非常厉害,你可以通过 Cron 表达式进行设置定时任务每天或者每个月什么时候执行等等操作。 |
| 14 | +> |
| 15 | +> 推荐一个在线Cron表达式生成器:[http://cron.qqe2.com/](http://cron.qqe2.com/) |
| 16 | +
|
| 17 | +```java |
| 18 | +import org.slf4j.Logger; |
| 19 | +import org.slf4j.LoggerFactory; |
| 20 | +import org.springframework.scheduling.annotation.Scheduled; |
| 21 | +import org.springframework.stereotype.Component; |
| 22 | + |
| 23 | +import java.text.SimpleDateFormat; |
| 24 | +import java.util.Date; |
| 25 | +import java.util.concurrent.TimeUnit; |
| 26 | + |
| 27 | +/** |
| 28 | + * @author shuang.kou |
| 29 | + */ |
| 30 | +@Component |
| 31 | +public class ScheduledTasks { |
| 32 | + private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class); |
| 33 | + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); |
| 34 | + |
| 35 | + /** |
| 36 | + * fixedRate:固定速率执行。每5秒执行一次。 |
| 37 | + */ |
| 38 | + @Scheduled(fixedRate = 5000) |
| 39 | + public void reportCurrentTimeWithFixedRate() { |
| 40 | + log.info("Current Thread : {}", Thread.currentThread().getName()); |
| 41 | + log.info("Fixed Rate Task : The time is now {}", dateFormat.format(new Date())); |
| 42 | + } |
| 43 | + |
| 44 | + /** |
| 45 | + * fixedDelay:固定延迟执行。距离上一次调用成功后2秒才执。 |
| 46 | + */ |
| 47 | + @Scheduled(fixedDelay = 2000) |
| 48 | + public void reportCurrentTimeWithFixedDelay() { |
| 49 | + try { |
| 50 | + TimeUnit.SECONDS.sleep(3); |
| 51 | + log.info("Fixed Delay Task : The time is now {}", dateFormat.format(new Date())); |
| 52 | + } catch (InterruptedException e) { |
| 53 | + e.printStackTrace(); |
| 54 | + } |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * initialDelay:初始延迟。任务的第一次执行将延迟5秒,然后将以5秒的固定间隔执行。 |
| 59 | + */ |
| 60 | + @Scheduled(initialDelay = 5000, fixedRate = 5000) |
| 61 | + public void reportCurrentTimeWithInitialDelay() { |
| 62 | + log.info("Fixed Rate Task with Initial Delay : The time is now {}", dateFormat.format(new Date())); |
| 63 | + } |
| 64 | + |
| 65 | + /** |
| 66 | + * cron:使用Cron表达式。 每分钟的1,2秒运行 |
| 67 | + */ |
| 68 | + @Scheduled(cron = "1-2 * * * * ? ") |
| 69 | + public void reportCurrentTimeWithCronExpression() { |
| 70 | + log.info("Cron Expression: The time is now {}", dateFormat.format(new Date())); |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +``` |
| 75 | + |
| 76 | +### 2. 启动类上加上`@EnableScheduling`注解 |
| 77 | + |
| 78 | +在 SpringBoot 中我们只需要在启动类上加上`@EnableScheduling`便可以启动定时任务了。 |
| 79 | + |
| 80 | +```java |
| 81 | +@SpringBootApplication |
| 82 | +@EnableScheduling |
| 83 | +public class DemoApplication { |
| 84 | + |
| 85 | + public static void main(String[] args) { |
| 86 | + SpringApplication.run(DemoApplication.class, args); |
| 87 | + } |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +### 3. 自定义线程池执行 scheduled task |
| 92 | + |
| 93 | +默认情况下,`@Scheduled`任务都在Spring创建的大小为1的默认线程池中执行,你可以通过在加了`@Scheduled`注解的方法里加上下面这段代码来验证。 |
| 94 | + |
| 95 | +```java |
| 96 | +logger.info("Current Thread : {}", Thread.currentThread().getName()); |
| 97 | +``` |
| 98 | + |
| 99 | +你会发现加上上面这段代码的定时任务,每次运行都会输出: |
| 100 | + |
| 101 | +``` |
| 102 | +Current Thread : scheduling-1 |
| 103 | +``` |
| 104 | + |
| 105 | +如果我们需要自定义线程池执行话只需要新加一个实现`SchedulingConfigurer`接口的 `configureTasks` 的类即可,这个类需要加上 `@Configuration` 注解。 |
| 106 | + |
| 107 | +```java |
| 108 | +@Configuration |
| 109 | +public class SchedulerConfig implements SchedulingConfigurer { |
| 110 | + private final int POOL_SIZE = 10; |
| 111 | + |
| 112 | + @Override |
| 113 | + public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { |
| 114 | + ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); |
| 115 | + |
| 116 | + threadPoolTaskScheduler.setPoolSize(POOL_SIZE); |
| 117 | + threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-"); |
| 118 | + threadPoolTaskScheduler.initialize(); |
| 119 | + |
| 120 | + scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler); |
| 121 | + } |
| 122 | +} |
| 123 | +``` |
| 124 | + |
| 125 | +通过上面的验证的方式输出当前线程的名字会改变。 |
| 126 | + |
0 commit comments