Spring Boot 的定时任务非常简单:
@Component
public class SchedulingConfig {
/*
@Scheduled(fixedRate = 5000) :上一次开始执行时间点之后5秒再执行
@Scheduled(fixedDelay = 5000) :上一次执行完毕时间点之后5秒再执行
@Scheduled(initialDelay=1000, fixedRate=5000) :第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
@Scheduled(cron="0/5 * * * * ?") :通过cron表达式定义规则
*/
@Scheduled(cron = "0/5 * * * * ?") // 每10秒执行一次
public void scheduler() {
System.out.println(Thread.currentThread().getName() + " scheduler");
}
}
启动类:
@EnableScheduling // 启用定时任务
public class ApplicationBoot {
public static void main(String[] args) {
SpringApplication.run(ApplicationBoot.class, args);
}
}
注意,@EnableScheduling这个一定要加上;否则,不会定时启动任务。
@Scheduled注解用来标注一个定时任务方法,支持多种参数:
(1)cron:cron表达式,指定任务在特定时间执行;
(2)fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
(3)fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
(4)fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
(5)fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
(6)initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
(7)initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;
(8)zone:时区,默认为当前时区,一般没有用到。
默认情况下,定时任务是单线程处理的。可以跟代码EnableScheduling -> SchedulingConfiguration -> ScheduledAnnotationBeanPostProcessor -> ScheduledTaskRegistrar, 在ScheduledTaskRegistrar中由taskScheduler
来执行任务。
在ScheduledTaskRegistrar中有setScheduler/setTaskScheduler方法来设置这个属性,方式有很多。
一种方式是使用SchedulingConfigurer接口:
@Configuration
//所有的定时任务都放在一个线程池中,定时任务启动时使用不同都线程。
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//设定一个长度10的定时任务线程池
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}
至于这个为啥生效,请参看ScheduledAnnotationBeanPostProcessor#finishRegistration方法:
private void finishRegistration() {
if (this.scheduler != null) {
this.registrar.setScheduler(this.scheduler);
}
if (this.beanFactory instanceof ListableBeanFactory) {
Map<String, SchedulingConfigurer> configurers =
((ListableBeanFactory) this.beanFactory).getBeansOfType(SchedulingConfigurer.class);
for (SchedulingConfigurer configurer : configurers.values()) {
configurer.configureTasks(this.registrar);
}
}
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
try {
// Search for TaskScheduler bean...
this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, false));
}
catch (NoUniqueBeanDefinitionException ex) {
logger.debug("Could not find unique TaskScheduler bean", ex);
try {
this.registrar.setTaskScheduler(resolveSchedulerBean(TaskScheduler.class, true));
}
catch (NoSuchBeanDefinitionException ex2) {
if (logger.isInfoEnabled()) {
logger.info("More than one TaskScheduler bean exists within the context, and " +
"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " +
"(possibly as an alias); or implement the SchedulingConfigurer interface and call " +
"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +
ex.getBeanNamesFound());
}
}
}
catch (NoSuchBeanDefinitionException ex) {
logger.debug("Could not find default TaskScheduler bean", ex);
// Search for ScheduledExecutorService bean next...
try {
this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, false));
}
catch (NoUniqueBeanDefinitionException ex2) {
logger.debug("Could not find unique ScheduledExecutorService bean", ex2);
try {
this.registrar.setScheduler(resolveSchedulerBean(ScheduledExecutorService.class, true));
}
catch (NoSuchBeanDefinitionException ex3) {
if (logger.isInfoEnabled()) {
logger.info("More than one ScheduledExecutorService bean exists within the context, and " +
"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " +
"(possibly as an alias); or implement the SchedulingConfigurer interface and call " +
"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +
ex2.getBeanNamesFound());
}
}
}
catch (NoSuchBeanDefinitionException ex2) {
logger.debug("Could not find default ScheduledExecutorService bean", ex2);
// Giving up -> falling back to default scheduler within the registrar...
logger.info("No TaskScheduler/ScheduledExecutorService bean found for scheduled processing");
}
}
}
this.registrar.afterPropertiesSet();
}
除了上述方式还有:
@Bean
public TaskScheduler taskScheduler(){
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(2);
taskScheduler.setThreadNamePrefix("scheduler-pool-");
return taskScheduler;
}
至于为什么这样就可以设置定时任务使用多线程,可以认真跟下源码看看。
本文介绍如何在SpringBoot中配置和使用定时任务,包括@Scheduled注解的各种参数详解及多线程配置方法。
1138

被折叠的 条评论
为什么被折叠?



