獲取Java後端專案的所有controller介面資訊(一)
highlight: monokai
「這是我參與2022首次更文挑戰的第1天,活動詳情檢視:2022首次更文挑戰」
前言
在我們進行後端業務開發時,一個經常需要的小功能就是去獲取我們所有編寫的介面及其請求資訊。可以用於介面測試,或者開發一些自定義的工具。
在開發過程中,我們一般會配置swagger來對於我們的controller進行測試,也經常會使用postman、curl等工具來模擬傳送請求,但是很多時候這些工具並不能滿足我們的所有需求,需要進行定製化開發。例如筆者所在的團隊,除了日常使用swagger之外,同時基於所有的介面資訊維護了一個工具來方便進行一些定製化的需求開發、日常的業務維護以及線上問題的處理。
那麼如何獲取所需要的介面資訊呢?
結合所查詢的資訊,以及筆者的親身實踐,大致總結了以下三種方法
1. 通過 RequestMappingHandlerMapping
2. 通過 Swagger
3. 通過 Spring Boot Actuator
作為一個系列文章,本文章首先介紹最基礎的方法——通過 RequestMappingHandlerMapping
獲取
什麼是 RequestMappingHandlerMapping
直接看原始碼註釋
java
/**
* Creates {@link RequestMappingInfo} instances from type and method-level
* {@link RequestMapping @RequestMapping} annotations in
* {@link Controller @Controller} classes.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Sam Brannen
* @since 3.1
*/
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
implements MatchableHandlerMapping, EmbeddedValueResolverAware {
......
}
正如註釋中所說,該類用於處理被 @Controller
所註解類中型別和方法級別的 @RequestMapping
並建立 RequestMappingInfo
例項,即用來建立並儲存所有的請求對映資訊。而在參考文件2中對其的描述如下
The RequestMappingHandlerMapping is used to maintain the mapping of the request URI to the handler. Once the handler is obtained, the DispatcherServlet dispatches the request to the appropriate handler adapter, which then invokes the handlerMethod().
即儲存了從請求路徑到對應handler的對映,DispatcherServlet
將請求交給 RequestMappingHandlerAdapter
來處理,呼叫對應儲存的 handle
方法
RequestMappingInfo
而 RequestMappingInfo
中儲存了哪些東西呢, 我們看原始碼註釋
java
/**
* Request mapping information. Encapsulates the following request mapping conditions:
* <ol>
* <li>{@link PatternsRequestCondition}
* <li>{@link RequestMethodsRequestCondition}
* <li>{@link ParamsRequestCondition}
* <li>{@link HeadersRequestCondition}
* <li>{@link ConsumesRequestCondition}
* <li>{@link ProducesRequestCondition}
* <li>{@code RequestCondition} (optional, custom request condition)
* </ol>
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
*/
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
......
}
可以看出,其封裝瞭如下幾個資訊
PatternsRequestCondition
請求路徑資訊RequestMethodsRequestCondition
http方法資訊ParamsRequestCondition
query或者表單資訊HeadersRequestCondition
請求頭資訊HeadersRequestCondition
請求的Content-Type資訊ProducesRequestCondition
所需的Accept
資訊- 其他自定義的請求條件
因此一個很簡單的想法便可以從腦海中浮現,如果在SpringMVC啟動完成之後,我們去獲取 RequestMappingHandlerMapping
物件,便可以從中獲取到所有的介面資訊
如何做到呢?監聽容器啟動事件!
ApplicationListener
和 @EventListener
ApplicationListener
介面用於實現容器的事件監聽,其設計採用觀察者模式,需要實現 onApplicationEvent
方法,其中泛型 E
即為所關心的容器事件,其他事件會被過濾
```java
public interface ApplicationListener
/*
* Handle an application event.
* @param event the event to respond to
/
void onApplicationEvent(E event);
}
``
為了方便,也可以使用註解
@EventListener` 來進行實現
具體實現
直接上程式碼,其中隱藏自定義處理的內容
```java
@Slf4j
@Component
public class FrontToolListener implements ApplicationListener
private static final String REQUEST_BEAN_NAME = "requestMappingHandlerMapping";
// 實現事件監聽方法
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 需要暴露資訊,因此線上環境不掃描
if (判斷是否是線上環境) {
log.info("線上環境,不掃描controller");
return;
}
// 判斷RequestMappingHandlerMapping是否存在,若不存在則不掃描
ApplicationContext applicationContext = event.getApplicationContext();
if (!applicationContext.containsBean(REQUEST_BEAN_NAME)) {
log.info("{}不存在, 掃描跳過", REQUEST_BEAN_NAME);
return;
}
log.info("{}存在,開始掃描controller方法", REQUEST_BEAN_NAME);
// 獲取所有的介面方法資訊
RequestMappingHandlerMapping requestMapping =
applicationContext.getBean(REQUEST_BEAN_NAME, RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> infoMap = requestMapping.getHandlerMethods();
// 省略自定義處理資訊
......
}
} ```
一些需要注意的問題
- 筆者自定義工具需要暴露介面資訊,故線上環境不允許進行掃描,否則存在安全性問題,預發環境原則上也不允許進行掃描,除非你可以保證預發環境不會被外部訪問
-
在某些專案內可能不存在
RequestMappingHandlerMapping
,需要手動進行注入,什麼情況下不存在筆者還在研究中, 注入的程式碼如下 ```java @Slf4j @EnableWebMvc @Configuration public class FrontToolConfig implements WebMvcConfigurer {@Bean @ConditionalOnMissingBean(name = "requestMappingHandlerMapping") public RequestMappingHandlerMapping requestMappingHandlerMapping() { log.info("RequestMappingHandlerMapping不存在,開始注入"); return new RequestMappingHandlerMapping(); }
`` 3.
ContextRefreshedEvent` 事件可能會觸發多次,導致我們的監聽函式多次被執行,其本質是因為存在多個ioc容器從而多次觸發容器事件,解決方法可以參考這篇文章 實現ApplicationListener事件被觸發兩次的問題 或者自己新增一個static的bool值來標識是否已經處理完成
參考文件
- 獲取Java後端專案的所有controller介面資訊(一)
- C | 指標陣列與陣列指標&記憶體分佈
- 自動化測試框架指南
- 六月獲版號新遊戲中,部分遊戲公司狀態異常,有公司已登出
- 淺析C 的函數語言程式設計
- Flutter Laravel開發的微信風格的及時通訊系統
- 賈躍亭國內關聯企業半數已登出
- 萬門教育被曝關門跑路,CEO童哲名下過半企業已登出
- 已登出手機號無法核驗行程,健康寶如何換綁手機號?看這裡
- 顯示卡公司 3dfx 不會迴歸了:推特假賬號已登出,英偉達否認該訊息
- 吳亦凡及其工作室賬號已登出 新華社:吳亦凡事件給演藝界敲響警鐘
- 香飄飄陷新品銷量之困 招股書披露的大供應商已登出
- 香飄飄陷新品銷量之困 招股書披露的大供應商已登出
- Web應用程式 [new_system] 註冊了JDBC驅動程式 [com.mysql.jdbc.Driver],但在Web應用程式停止時無法登出它。 為防止記憶體洩漏,JDBC驅動程式已被強制取消註冊
- 電子煙監管加磅!我國超1800家相關企業已登出或吊銷
- 瑞幸咖啡相關企業今年已登出吊銷101家
- 影院復工“難”:場均觀影不足1人、全線再度被叫停、2200多家已登出
- 影院復工“難”:場均觀影不足1人、全線再度被叫停、2200多家已登出