spring boot的定時任務很是簡單,只須要在啓動類中加上@EnableScheduling註解,而後在對應的方法上配置@Scheduled就能夠了,系統會自動處理並按照Scheduled中的配置定時執行方法。html
可是在啓動項目的時候,發生了很詭異的現象,有兩個TaskScheduler/ScheduledExecutorService的異常打印了出來。可是系統並無受影響,依然正常啓動,並且定時任務也是正常執行。java
2018-09-29 15:54:05,187 DEBUG main org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor [//] Could not find default TaskScheduler bean org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.scheduling.TaskScheduler' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:996) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.resolveSchedulerBean(ScheduledAnnotationBeanPostProcessor.java:278) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:221) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:200) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:94) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:383) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:337) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:882) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) at com.cmft.RunApp.main(RunApp.java:34) 2018-09-29 15:54:05,190 DEBUG main org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor [//] Could not find default ScheduledExecutorService bean org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.util.concurrent.ScheduledExecutorService' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:996) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.resolveSchedulerBean(ScheduledAnnotationBeanPostProcessor.java:278) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:241) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:200) at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:94) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:383) at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:337) at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:882) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:545) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:737) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:370) at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) at com.cmft.RunApp.main(RunApp.java:34) 2018-09-29 15:54:05,190 INFO main org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor [//] No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
雖然沒有影響系統,可是有異常看着總歸很難受,因而嘗試去探究下這個異常的緣由。spring
經過觀察咱們這兩個異常是日誌模塊打印出來的debug級別日誌框架
2018-09-29 15:54:05,187 DEBUG main org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor [//] Could not find default TaskScheduler bean 2018-09-29 15:54:05,190 DEBUG main org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor [//] Could not find default ScheduledExecutorService bean
並且都是在ScheduledAnnotationBeanPostProcessor類中打印出來。看類的名字咱們大概能猜到這是@Scheduled註解的處理類。this
根據日誌內容咱們定位到這個問題是由finishRegistration()方法打印出來。debug
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); Iterator var2 = configurers.values().iterator(); while(var2.hasNext()) { SchedulingConfigurer configurer = (SchedulingConfigurer)var2.next(); 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 { this.registrar.setTaskScheduler((TaskScheduler)this.resolveSchedulerBean(TaskScheduler.class, false)); } catch (NoUniqueBeanDefinitionException var8) { try { this.registrar.setTaskScheduler((TaskScheduler)this.resolveSchedulerBean(TaskScheduler.class, true)); } catch (NoSuchBeanDefinitionException var7) { if (this.logger.isInfoEnabled()) { this.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: " + var8.getBeanNamesFound()); } } } catch (NoSuchBeanDefinitionException var9) { this.logger.debug("Could not find default TaskScheduler bean", var9); try { this.registrar.setScheduler(this.resolveSchedulerBean(ScheduledExecutorService.class, false)); } catch (NoUniqueBeanDefinitionException var5) { try { this.registrar.setScheduler(this.resolveSchedulerBean(ScheduledExecutorService.class, true)); } catch (NoSuchBeanDefinitionException var4) { if (this.logger.isInfoEnabled()) { this.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: " + var5.getBeanNamesFound()); } } } catch (NoSuchBeanDefinitionException var6) { this.logger.debug("Could not find default ScheduledExecutorService bean", var6); this.logger.info("No TaskScheduler/ScheduledExecutorService bean found for scheduled processing"); } } } this.registrar.afterPropertiesSet(); }
看代碼咱們會發現,spring會從先從註冊過的bean中找任務調度器TaskScheduler日誌
this.registrar.setTaskScheduler((TaskScheduler)this.resolveSchedulerBean(TaskScheduler.class, false));
若是獲取不到會拋出異常,而後打印出來code
this.logger.debug("Could not find default TaskScheduler bean", var9);
而後繼續尋找定時任務的執行類ScheduledExecutorServicehtm
this.registrar.setScheduler(this.resolveSchedulerBean(ScheduledExecutorService.class, false));
若是找不到,會繼續拋出異常並打印出來ci
catch (NoSuchBeanDefinitionException var6) { this.logger.debug("Could not find default ScheduledExecutorService bean", var6); this.logger.info("No TaskScheduler/ScheduledExecutorService bean found for scheduled processing"); }
如此,便看到開頭咱們看到的兩個異常。
看後面代碼咱們會發現,若是註冊的bean中找不到,會調用scheduleTasks()方法初始化TaskScheduler,因此這兩個異常並不會影響系統。可能spring 的開發者是想借此提醒開發人員要本身在系統中註冊要使用的bean,而不是依賴框架來默認初始化。
第一種是眼不見爲淨法,簡單粗暴地修改日誌級別就好。
log4j.logger.org.springframework.scheduling = INFO
這樣debug級別的日誌就不會被打印出來,只有最後的info級別日誌纔會被打印。
既然提示的異常是註冊的bean中找不到TaskScheduler,那麼咱們就註冊TaskScheduler。
@Bean public TaskScheduler scheduledExecutorService() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(8); scheduler.setThreadNamePrefix("scheduled-thread-"); return scheduler; }