爲防止打臉,先寫明版本:spring boot 2.2.2.RELEASEjava
spring boot 中自帶了一個輕量級的任務調度框架,使用也很是簡單。spring
@EnableScheduling
,固然須要放在一個能夠被掃描到的類上,好比啓動類、使用了@Configuration
的配置類。固然你要放在一個@Component
的類上除了不太規範,我也無話可說。在須要定時運行的方法上加上@Scheduled
註解,並設置調度方式,支持微信
就這麼簡單。框架
如今有兩個任務A和Bide
任務A在5點執行,並耗時2個小時ui
@Scheduled(cron = "0 0 5 * * *") public void taskA() throws InterruptedException { log.info("taskA running"); Thread.sleep(2 * 60 * 60 * 1000);//模擬任務耗時,2個小時 }
任務B在6點執行spa
@Scheduled(cron = "0 0 6 * * *") public void taskB() { log.info("taskB running"); }
靈魂一問:任務B能按預期在6點執行嗎?線程
若是以爲能正常執行,怕是已經忘記了標題。code
先說結論:任務B不能在6點執行,由於調度器是的線程池大小爲1。orm
不用想,確定是spring boot 自動配置的。
先看註解@EnableScheduling
,註釋中有寫到
By default, will be searching for an associated scheduler definition: either a unique org.springframework.scheduling.TaskScheduler bean in the context, or a TaskScheduler bean named "taskScheduler" otherwise; the same lookup will also be performed for a java.util.concurrent.ScheduledExecutorService bean. If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar. When more control is desired, a @Configuration class may implement SchedulingConfigurer. This allows access to the underlying ScheduledTaskRegistrar instance.
整理下,大概意思是,默認狀況下,會尋找一個調度器,按照如下順序
org.springframework.scheduling.TaskScheduler
類型的beantaskScheduler
的org.springframework.scheduling.TaskScheduler
類型的beanjava.util.concurrent.ScheduledExecutorService
類型的beantaskScheduler
的java.util.concurrent.ScheduledExecutorService
類型的bean若是想掌控更多,能夠寫一個實現了SchedulingConfigurer
接口的配置類。若是在這個配置類設置了調度器,就不會再尋找了。
看上去應該是走到了第5種狀況。
@EnableScheduling
引入了SchedulingConfiguration
,SchedulingConfiguration
中定義了一個ScheduledAnnotationBeanPostProcessor
類型的bean。
@Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class SchedulingConfiguration { @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() { return new ScheduledAnnotationBeanPostProcessor(); } }
設置調度器的代碼在finishRegistration
方法中。
跟代碼發現實際上是在執行第一種狀況時就已經知足了。
這個bean是那裏定義的?
一(全)番(憑)摸(運)索(氣),找到了一個自動配置類TaskSchedulingAutoConfiguration
,其中定義了ThreadPoolTaskScheduler
類型的bean。
看一下上面的條件
org.springframework.context.annotation.internalScheduledAnnotationProcessor
的bean才加載,而這個名稱就是SchedulingConfiguration
中定義ScheduledAnnotationBeanPostProcessor
的名稱。SchedulingConfigurer
、TaskScheduler
、ScheduledExecutorService
這些類型的bean時才加載。這也是爲了保持擴展性。開發者定義了相關的bean,框架就不自動配置了。@Bean @ConditionalOnBean( name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"} ) @ConditionalOnMissingBean({SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class}) public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) { return builder.build(); }
那麼如何修改調度器線程池大小呢
在TaskSchedulingAutoConfiguration
類中定義了上面方法須要的TaskSchedulerBuilder
@Bean @ConditionalOnMissingBean public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) { TaskSchedulerBuilder builder = new TaskSchedulerBuilder(); builder = builder.poolSize(properties.getPool().getSize()); Shutdown shutdown = properties.getShutdown(); builder = builder.awaitTermination(shutdown.isAwaitTermination()); builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); builder = builder.threadNamePrefix(properties.getThreadNamePrefix()); builder = builder.customizers(taskSchedulerCustomizers); return builder; }
能夠看到線程池大小是經過讀配置設置的,也就是設置spring.task.scheduling.pool.size
。
固然上述方法是沿用spring boot 自動配置的,你也能夠本身定義,只要搞清楚尋找的優先級就沒問題了。
看到了這裏必定是真愛了,關注微信公衆號【憨憨的春天】第一時間獲取更新