Spring Boot 定时任务

  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 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;
}

  至于为什么这样就可以设置定时任务使用多线程,可以认真跟下源码看看。

你可能感兴趣的:(-------【Spring,Boot】)