Spring Boot Actuator
是spring boot
項目一個監控模塊,提供了不少原生的端點,包含了對應用系統的自省和監控的集成功能,好比應用程序上下文裏所有的Bean、運行情況檢查、健康指標、環境變量及各種重要度量指標等等,以圖形化界面的方式展現這些信息,經過這些監控信息,咱們就能隨時瞭解應用的運行狀況了。java
做用:能夠經過監控運行狀態檢查獲取應用的運行狀態,潛在問題等。能夠更具這些且在風險對項目進行優化,排除問題保證項目的運行。能夠經過監控度量指標獲取應用內存佔用,線程數量,垃圾回收過程對項目進行深刻分析。git
在項目中引入Actuator依賴,該以來由SprngBoot官方提供。github
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-actuator</artifactId> 4 </dependency>
當項目中引入了Actuator依賴後,那麼當前的項目就表示擁有了度量指標監控能力了,啓動SpringBoot項目,控制檯以下:web
框起來的那段內容表示:SpringBoot監控已經默認暴露了兩個基礎端點,可供咱們訪問獲取應用監控數據,基礎訪問路徑是"/actuator"spring
輸入訪問路徑:localhost:8080/actuator 結果以下:(爲便於查看,我已將JSON結果格式化)編程
1 { 2 "_links": { 3 "self": { 4 "href": "http://localhost:8080/actuator", // 基礎訪問地址 5 "templated": false 6 }, 7 "health-path": { 8 "href": "http://localhost:8080/actuator/health/{*path}", 9 "templated": true 10 }, 11 "health": { 12 "href": "http://localhost:8080/actuator/health", // 暴露的端點一 (訪問URL) 13 "templated": false 14 }, 15 "info": { 16 "href": "http://localhost:8080/actuator/info", // 暴露的端點二 (訪問URL) 17 "templated": false 18 } 19 } 20 }
那麼這些暴露的URL訪問後分別表明什麼呢?Actuator提供了13個接口,能夠分爲三大類:配置接口、度量接口和其它接口,具體以下表:json
HTTP 方法 | 路徑 | 描述 |
---|---|---|
GET | /autoconfig | 提供了一份自動配置報告,記錄哪些自動配置條件經過了,哪些沒經過 |
GET | /configprops | 描述配置屬性(包含默認值)如何注入Bean緩存 ●prefix屬性表明 了屬性的配置前綴 |
GET | /beans | 描述應用程序上下文裏所有的Bean,以及它們的關係多線程 ●bean:Bean的名稱 |
GET | /dump | 獲取線程活動的快照 |
GET | /env | 獲取所有環境屬性。包括:環境變量、JVM屬性.應用的配置配置。命令行中的參數等 |
GET | /env/{name} | 根據名稱獲取特定的環境屬性值。/env接口還能用來獲取單個屬性的值。只須要在請求時在/env/+屬性名便可。 |
GET | /health | 報告應用程序的健康指標(運行狀態),這些值由HealthIndicator的實現類提供.(默認暴露的接口) |
GET | /info | 獲取應用程序的自定義的定製信息,這些信息由info打頭的屬性提供。默認狀況下.該端點只會返回一個空的json內容,咱們能夠在application.properties配置文件中經過info前騷來設置一些屬性(默認暴露的接口) |
GET | /mappings | 描述所有的URI路徑,以及它們和控制器(包含Actuator端點)的映射關係,羅列出應用程序發佈的所有接口。 ●bean屬性標識了 該映射關係的請求處理器 |
GET | /metrics | 報告各類應用程序度量信息,好比內存用量,線程信息,垃圾回收信息,HTTP請求計數等 |
GET | /metrics/{name} | 報告指定名稱的應用程序度量值 |
POST | /shutdown | 關閉應用程序,要求endpoints.shutdown.enabled設置爲true |
GET | /trace | 提供基本的HTTP請求跟蹤信息(時間戳、HTTP頭等) |
訪問一個試試?localhost:8080/actuator/health 訪問後結果:運行狀態爲正常運行(說明:Actuator監控獲取的全部數據都是JSON格式的。)
1 {"status":"UP"}
那麼若是但願訪問其餘接口怎麼辦?,默認只開啓了info、health
兩個端點,須要額外開啓端點,須要額外去配置的!!!
1 #配置訪問端點的根路徑 2 management: 3 endpoints: 4 web: 5 # 配置訪問端點的根路徑,默認是/actuator 6 #base-path: /actuator 7 exposure: 8 #配置開啓其餘端點的URI,開啓全部的端點訪問: *,也能夠指定開啓端點訪問:如: /beans, /env 9 include: "*" 10 # - /beans 11 # - /env 12 #配置排除其餘端點的URI(排除即不開啓) 13 #exclude: 14 # - /beans 15 # - /env
重啓SpringBoot服務,以下:
具體訪問測試就不演示了,Actuator監控獲取的全部數據都是JSON格式的,能夠本身訪問測試後經過網絡工具格式化JSON。
Actuator來監控Spring Boot應用,其提供了許多REST接口來查看應用的信息。但其返回的是大量的JSON格式數據,信息看上去不直觀也不易於理解。Spring Boot Admin(SBA)是一款基於Actuator開發的開源軟件(是一個針對spring-boot
的actuator
接口進行UI美化封裝的監控工具),能夠實現圖形化界面的方式展現Spring Boot應用的配置信息、Beans信息、環境屬性、線程信息、JVM情況等。官方說明文檔點這裏。選擇版本文檔說明,內有詳情使用說明。
SpringBootAdmin的使用是須要創建服務端與客戶端的。Spring Boot Admin
包含admin-server
與admin-client
兩個組件,admin-server
經過採集actuator
端點數據,顯示在spring-boot-admin-ui
上。
服務端:獨立的項目,會將蒐集到的數據在本身的圖形界面中展現。依賴admin-server
客戶端:須要監控的項目。依賴Actuator,admin-client
對應關係:一個服務端能夠監控多個客戶端。
舒適提示:服務端屬於一個獨立SpringBoot的項目(新建項目)。
1 <!-- spring-boot-admin-服務端依賴 --> 2 <dependency> 3 <groupId>de.codecentric</groupId> 4 <artifactId>spring-boot-admin-starter-server</artifactId> 5 <version>2.3.1</version> 6 </dependency>
1 server: 2 #servlet: 3 # 配置訪問路徑(可選) 4 #context-path: /admin-server 5 # 配置端口 6 port: 9090
1 @SpringBootApplication 2 @EnableAdminServer 3 public class SpringbootAdminServerApplication {
由於還沒添加客戶端,因此監控列表裏是空的,接下來建立一個Spring Boot應用做爲客戶端。
admin-server
經過採集actuator
端點數據,將信息解析展現在UI界面的。那麼客戶端就須要依賴Actuator和admin-clietn。
1 <!-- spring-boot-admin-starter-client客戶端依賴:注意要與服務端版本一致 --> 2 <dependency> 3 <groupId>de.codecentric</groupId> 4 <artifactId>spring-boot-admin-starter-client</artifactId> 5 <version>${spring-boot-admin.version}</version> 6 </dependency>
注意:1.版本要與服務端一致。2.客戶端項目依賴不能少了Actuator。
1 #配置訪問端點的根路徑 2 management: 3 endpoints: 4 web: 5 # 配置訪問端點的根路徑,默認是/actuator 6 #base-path: /actuator 7 exposure: 8 #配置開啓其餘端點的URI,開啓全部的端點訪問: *,也能夠指定開啓端點訪問:如: /beans, /env 9 include: "*" 10 # - /beans 11 # - /env 12 #配置排除其餘端點的URI(排除即不開啓) 13 #exclude: 14 # - /beans 15 # - /env 16 17 spring: 18 boot: 19 admin: 20 client: 21 # 配置客戶端,被監控的服務端地址(官方說明也很詳細的,這個是必須配置的) 22 url: 23 - http://localhost:9090
點擊左上「應用牆」進入SpringBootAdmin主頁,顯示運行時間,項目個數。點擊進入詳情頁,便可已圖形報表UI界面方式顯示全部監控信息: 如上的操做更多的多是涉及到了測試/運維的問題,因此這裏就不深究了,但某些時候須要咱們開發人員配和實現更多操做,例如郵件方式發送檢測日誌,信息等。詳情參考SpringBootAdmin
實際開發中,有一些業務可能和實際業務無關,但又不能沒有,例如:註冊新用戶,當即送積分(沒有點擊領取但積分已到帳),或下單成功,發送push消息等等。
一般咱們開發的程序都是同步調用的,即程序按照代碼的順序一行一行的逐步往下執行,每一行代碼都必須等待上一行代碼執行完畢才能開始執行。而異步編程則沒有這個限制,代碼的調用再也不是阻塞的。因此在一些情景下,經過異步編程能夠提升效率,提高接口的吞吐量。
使用異步的好處?就拿註冊用戶送積分來講:
不使用異步調用,即同步調用測試。
1 @Service 2 public class AsynService { 3 4 /** 5 * 註冊方法 6 */ 7 public void register() { 8 System.out.println("註冊成功......."); 9 } 10 /** 11 * 異步方法送積分 12 */ 13 public void asynIntegral() { 14 try { 15 Thread.sleep(3000);// 休息三秒 16 } catch (InterruptedException e) { 17 // TODO Auto-generated catch block 18 e.printStackTrace(); 19 } 20 System.out.println("送積分100分....執行者線程名爲:"+Thread.currentThread().getName()); 21 } 22 23 }
1 @RestController 2 @Slf4j // 獲取log對象,Lombok插件中的註解 3 public class AsynController { 4 5 @Autowired 6 private AsynService asynService; 7 8 @RequestMapping("/register") 9 public String asynTest() { 10 long startTmie = System.currentTimeMillis(); 11 // 註冊邏輯:調用註冊方法 12 asynService.register(); 13 // 調用送積分方法 14 asynService.asynIntegral(); 15 long endtTmie = System.currentTimeMillis(); 16 log.info("消耗時間:"+(endTime-starttTmie)); 17 return "ok"; 18 } 19 20 }
註冊成功.......
送積分100分....執行者線程名稱爲:http-nio-8080-exec-1
2020-12-02 20:00:15.112 INFO 4604 --- [nio-8080-exec-1] c.xsge123.app.controller.AsynController : 消耗時間:3002
結束語:在同步調用時,頁面不會馬上刷新註冊結果,只有註冊和送積分的功能所有執行完成後,頁面纔會顯示註冊通知。客戶需等待較長的時間。程序總耗時較長。
在同步代碼基礎上,新增配置類AsyncConfig,配置開啓異步調用,同時在須要使用異步調用的方法上使用註解@Async便可。
1 @Configuration // 將類注入到Spring容器中 2 @EnableAsync //開啓SpringBoot異步調用(針對異步調用的方法,開啓新線程),在啓動類上使用也能夠 3 public class AsyncConfig { 4 5 }
1 /** 2 * 異步方法送積分 3 */ 4 @Async // 標註當前方法爲異步方法 5 public void asynIntegral() { 6 try { 7 Thread.sleep(3000);// 休息3秒 8 } catch (InterruptedException e) { 9 // TODO Auto-generated catch block 10 e.printStackTrace(); 11 } 12 System.out.println("送積分100分...."+Thread.currentThread().getName()); 13 }
註冊成功....... 2020-12-02 20:18:11.764 INFO 4604 --- [nio-8080-exec-2] c.xsge123.app.controller.AsynController : 消耗時間:6 送積分100分....task-1
送積分100分....score-2
送積分100分....score-3
結束語:在異步調用的狀況下,頁面即刻響應註冊結果,無需等待,後臺等待3秒後,送積分程序顯示執行結果。
@Async註解,在默認狀況下,用的是SimpleAsyncTaskExecutor線程池,該線程池不是真正意義上的線程池,由於線程不可重用,每次調用都會新建一條線程。能夠經過控制檯日誌輸出查看,每次打印的線程名都是[task -1]、[task -2]、[task-3]、[task-4].....遞增的。
@Async註解異步框架提供有多種線程池支持:
SimpLeAsyncTaskExecutor:不是真的線程池,這個類不可重用線程,每次調用都會建立一個新的線程 。
SyncTaskExecutor:這個類沒有實現異步調用,只是一個同步操做。只適用於不須要多線程的地方
ConcurrentTaskExecutor:Executor的適配類,不推薦使用。若是ThreadPoolTaskExecutor不知足要求時,才用考慮使用這個類
ThreadPoolTaskScheduler:可使用cron表達式。
ThreadPoolTaskExecutor :最常使用,推薦。 其實質是對java.util.concurrent .ThreadPoolExecutor的包裝類。
1 @Configuration // 將類注入到Spring容器中 2 @EnableAsync //開啓SpringBoot異步調用(針對異步調用的方法,開啓新線程) 3 public class AsyncConfig { 4 5 @Bean(name = "scorePoolTaskExecutor") 6 public ThreadPoolTaskExecutor getScorePoolTaskExecutor() { 7 // 建立線程池對象 8 ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); 9 //核心線程數 10 taskExecutor.setCorePoolSize(10); 11 //線程池維護線程的最大數量,只有在緩衝隊列滿了以後纔會申請超過核心線程數的線程 12 taskExecutor.setMaxPoolSize(100); 13 //緩存隊列 14 taskExecutor.setQueueCapacity(50) ; 15 //許的空閒時間,當超過了核心線程出以外的線程在空閒時間到達以後會被銷燬 16 taskExecutor.setKeepAliveSeconds (200) ; 17 //.異步方法內部線程名稱 18 taskExecutor.setThreadNamePrefix("score-"); 19 /** 20 * 當線程池的任務緩存隊列已滿,而且線程池中的線程數目達到maximumPoolSize,若是還有任務到來就會採起任務拒絕策略 21 * 一般有如下四種策略: 22 * ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecuti onException異常。 23 * ThreadPoolExecutor.DiscardPolicy: 也是丟棄任務,可是不拋出異常。 24 * ThreadPoolExecutor. DiscardOldestPolicy: 丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程) 25 * ThreadPoolExecutor . CallerRunsPolicy:重試添加當前的任務,自動重複調用execute()方法,直到成功 26 */ 27 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 28 taskExecutor.initialize() ; 29 return taskExecutor; 30 } 31 32 }
1 /** 2 * 異步方法送積分 3 */ 4 @Async("scorePoolTaskExecutor") // 標註當前方法爲異步方法 5 public void asynIntegral() { 6 try { 7 Thread.sleep(3000); 8 } catch (InterruptedException e) { 9 // TODO Auto-generated catch block 10 e.printStackTrace(); 11 } 12 System.out.println("送積分100分...."+Thread.currentThread().getName()); 13 }
註冊成功....... 2020-12-02 20:45:57.898 INFO 4604 --- [nio-8080-exec-3] c.xsge123.app.controller.AsynController : 消耗時間:2 送積分100分....score-1 送積分100分....score-2 送積分100分....score-3
結束語:線程實現自定義