
HttpMethod雖然它被設(shè)計(jì)為final class而非enum(出于歷史兼容性考慮),但它的作用與枚舉完全一致:為 HTTP 協(xié)議中定義的 8 種標(biāo)準(zhǔn)請(qǐng)求方法提供類型安全的常量,并允許擴(kuò)展非標(biāo)準(zhǔn)方法。下面我將其拆解為三個(gè)層次,詳細(xì)解釋每一部分的設(shè)計(jì)意圖和實(shí)際用途。1. 類定義與整體設(shè)計(jì)publicfinalclassHttpMethodimplementsComparableHttpMethod,Serializable{// ...}final class:表示該類不能被繼承,確保所有實(shí)例的行為都是確定且統(tǒng)一的。ComparableHttpMethod:實(shí)現(xiàn)自然排序,基于方法名稱的字符串順序(如DELETEGET)。主要用于集合排序。Serializable:允許HttpMethod對(duì)象在網(wǎng)絡(luò)傳輸或序列化到磁盤時(shí)保持狀態(tài)(例如在分布式緩存或 RPC 調(diào)用中)。設(shè)計(jì)意圖:在 Spring 3.0 之前,HttpMethod是一個(gè)普通的enum。后來(lái)為了允許用戶自定義非標(biāo)準(zhǔn) HTTP 方法(如 WebDAV 的PROPFIND),Spring 將其改為final class,同時(shí)保留預(yù)定義常量。這種設(shè)計(jì)既提供了類型安全,又保持了擴(kuò)展性。2. 預(yù)定義常量(標(biāo)準(zhǔn) HTTP 方法)類中定義了 8 個(gè)public static final常量,對(duì)應(yīng) HTTP/1.1 規(guī)范(RFC 2616)及 PATCH(RFC 5789)中的所有方法:常量名對(duì)應(yīng)方法典型用途GETGET請(qǐng)求獲取資源(安全、冪等)HEADHEAD僅獲取響應(yīng)頭,不返回實(shí)體(安全、冪等)POSTPOST創(chuàng)建新資源或提交數(shù)據(jù)(非安全、非冪等)PUTPUT完整更新資源(冪等)PATCHPATCH部分更新資源(非冪等)DELETEDELETE刪除資源(冪等)OPTIONSOPTIONS查詢服務(wù)器支持的 HTTP 方法(安全、冪等)TRACETRACE回顯服務(wù)器收到的請(qǐng)求(用于診斷,常被禁用)每個(gè)常量的注釋都引用了相應(yīng)的 RFC 文檔,方便開(kāi)發(fā)者查閱標(biāo)準(zhǔn)。實(shí)現(xiàn)細(xì)節(jié):每個(gè)常量都是通過(guò)私有構(gòu)造器new HttpMethod("GET")創(chuàng)建的,因此所有預(yù)定義常量都是該類的單例實(shí)例。3. 核心靜態(tài)方法values()publicstaticHttpMethod[]values(){HttpMethod[]copy=newHttpMethod[values.length];System.arraycopy(values,0,copy,0,values.length);returncopy;}作用:返回所有預(yù)定義常量的副本數(shù)組,避免外部修改內(nèi)部數(shù)組。用法:類似枚舉的values(),通常用于遍歷或轉(zhuǎn)換為集合。valueOf(String method)publicstaticHttpMethodvalueOf(Stringmethod){Assert.notNull(method,"Method must not be null");returnswitch(method){case"GET"-GET;case"HEAD"-HEAD;// ...default-newHttpMethod(method);};}作用:將字符串轉(zhuǎn)換為HttpMethod對(duì)象。關(guān)鍵行為:如果字符串匹配預(yù)定義常量(區(qū)分大小寫,必須是大寫),則返回對(duì)應(yīng)的單例。如果字符串不匹配,則創(chuàng)建一個(gè)新的HttpMethod實(shí)例(例如"PROPFIND")。注意:這意味著HttpMethod.valueOf("get")會(huì)返回一個(gè)新對(duì)象,且該對(duì)象與HttpMethod.GET不相等(equals比較字符串名稱)。這種設(shè)計(jì)使得任何字符串都能被包裝為HttpMethod,但只有標(biāo)準(zhǔn)方法才擁有單例。4. 實(shí)例方法name()返回 HTTP 方法名稱的字符串(如"GET")。matches(String method)判斷當(dāng)前對(duì)象的方法名是否與給定字符串相等(區(qū)分大小寫)。等價(jià)于name().equals(method),但更語(yǔ)義化。compareTo(HttpMethod other)基于name的字典序進(jìn)行比較,符合Comparable契約。equals/hashCode/toString重寫自O(shè)bject,均基于name字段。因此兩個(gè)不同實(shí)例但名稱相同(如new HttpMethod("GET")和HttpMethod.GET)會(huì)被視為相等,但實(shí)際開(kāi)發(fā)中不會(huì)這樣使用。5. 設(shè)計(jì)亮點(diǎn)與實(shí)戰(zhàn)關(guān)聯(lián)類型安全與擴(kuò)展性的平衡類型安全:方法參數(shù)使用HttpMethod而非String,防止拼寫錯(cuò)誤。擴(kuò)展性:允許創(chuàng)建任意非標(biāo)準(zhǔn)方法對(duì)象,而無(wú)需修改類定義,適配了 WebDAV、自定義 REST 動(dòng)詞等場(chǎng)景。在 Spring 生態(tài)中的廣泛應(yīng)用RestTemplate、WebClient、@RequestMapping等均使用HttpMethod作為參數(shù)或?qū)傩?。在WebSocket 握手場(chǎng)景中,握手請(qǐng)求本身就是一個(gè) HTTP 升級(jí)請(qǐng)求,其方法通常是GET。因此HttpMethod.GET在HandshakeInterceptor中會(huì)被用來(lái)判斷請(qǐng)求類型。與你的聊天軟件的聯(lián)系在你的HandshakeInterceptor實(shí)現(xiàn)中,可以通過(guò)ServerHttpRequest.getMethod()獲取請(qǐng)求方法:if(request.getMethod()!=HttpMethod.GET)