在開發spring boot應用服務的時候,難免會使用到非同步任務及執行緒池。spring boot的執行緒池是可以自定義的,所以我們經常會在專案裡面看到類似於下面這樣的程式碼
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
executor.setMaxPoolSize(config.getMaxPoolSize());
executor.setQueueCapacity(config.getQueueCapacity());
executor.setThreadNamePrefix("TaskExecutePool-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.initialize();
return executor;
}
使用起來很方便,但是這樣做有幾個問題:
為了解決上述的問題,我開發了一個Spring Boot Starter(開源專案地址:https://gitee.com/hanxt/zimug-monitor-threadpool ),方便整合到Spring Boot專案裡面去。目標是:在不改變SpringBoot執行緒池的核心實現的基礎上,使其視覺化、易觀測、易設定、易使用。
需要說明的是:zimug-monitor-threadpool並未改變SpringBoot執行緒池的實現,只是在其基礎上新增了初始化階段的設定自動化載入,執行時的狀態監控。所以任何有關Spring Boot執行緒池執行時效能的討論,都與本文及其實現無關。
通過上文的專案地址獲取原始碼,然後maven編譯install本地m2倉庫。然後通過下面的maven座標引入
<dependency>
<groupId>com.zimug</groupId>
<artifactId>zimug-monitor-threadpool</artifactId>
<version>1.0</version>
</dependency>
如下設定spring boot YAML(application.yml)所示,設定了兩個執行緒池,分別是test、test2。當thread-pool.enable=true
的時候執行緒池設定生效。
thread-pool:
enable: true
poolLists:
- poolId: test #執行緒池唯一標識
poolName: 測試1 #執行緒池的中文描述,比如執行緒池給誰用?
coreSize: 5 #執行緒池初始化核心執行緒數量
maxSize: 10 #執行緒池最大執行緒容量
queueCapacity: 10 #執行緒池等待佇列的容量
- poolId: test2
poolName: 測試2
coreSize: 5
maxSize: 10
queueCapacity: 10
通過下面的這張圖理解上面的設定資訊
使用方式和SpringBoot 程式碼方式自定義執行緒池的使用方式是一樣的。使用@Async
註解的值是test,呼叫該註解標識的函數就會放入上文中設定的test執行緒池裡面去執行。
@Component
public class TestTask {
@Async("test") //注意這裡,test是執行緒池設定的poolId
public Future<String> test() throws Exception {
System.out.println("當前執行緒:" + Thread.currentThread().getName());
return new AsyncResult<>("測試任務");
}
}
在專案中引入zimug-monitor-threadpool之後,進行執行緒池設定,使用執行緒池。存取服務的/pool.html
即可獲取當前SpringBoot服務的執行緒池設定資訊,以及執行時狀態資訊。
zimug-monitor-threadpool的實現原理也非常簡單,簡單說一下原理,具體實現參考原始碼。
configurableBeanFactory.registerSingleton(pool.getPoolId(), taskExecutor);
ThreadPoolTaskExecutor memThreadPool = (ThreadPoolTaskExecutor) applicationContext.getBean(poolModel.getPoolId());
字母哥部落格:zimug.com