【API知識】一種你可能沒見過的Controller形式
前言
這裡分享一下我遇到的一個挺有意思的Controller形式,內容涉及@RequestMapping註解的原理。
實際案例
一、基本描述
專案甲中有多個模組,其中就有模組A和B。(這裡的模組指的是Maven的多模組子專案),專案乙、丙、丁可以引用模組A來訪問獨立部署的模組B
模組A => 關於與模組B通訊的協議定義
模組B => 可以獨立部署的專案
其中模組A中定義了一個FeignClient的介面用於訪問模組B的服務。
@FeignClient(name = "xx-service", url="http://xx-service:8080") public interface XXXService { @PostMapping("/some-url") public SomeResponse someOperation(@RequestBody SomeParam param); ... }
我們知道只要打上了@FeignClient註解,我們就可以直接在類中引入這個XXXService,然後呼叫它的方法。如果我們呼叫someOperation方法,那它就會根據服務名獲取到IP埠資訊,然後發HTTP請求到指定服務xx-service。
二、問題出現
按理說,模組B肯定有一個Controller來處理這個“/som-url”的請求。於是我全域性搜尋了模組B,發現怎麼找也找不到“/some-url”。
後來發現模組B中依賴於模組A,且有一個類實現了XXXService這個介面。這個類叫XXXServiceImpl。這個類既不叫xxxController,也不帶@Controller註解。
@ResponseBody @RequestMapping @Service public class XXXServiceImpl implements XXXService { @Override public SomeResponse someOperation(SomeParam param) { SomeResponse someResponse = new SomeResponse(); ... return someResponse; } ... }
看到@ResponseBody,@RequestMapping,@Service。在我看來這就是一個@RestController了。但是問題來了,還是沒有Mapping。
三、我的一個猜想
我想有沒有可能實現類繼承了介面方法上的註解,於是我看了下@PostMapping的元註解,發現並沒有@Inherited的註解。我也嘗試列印了XXXServiceImpl類someOperation方法上的註解,發現確實沒有。
四、問題解答
XXXServiceImpl確實充當了Controller。 關鍵在於針對@RequestMapping的掃描,會向上掃描類的所有父類和介面。 只要在介面或者父類的上方法上發現了@RequestMapping的註解,就認定這個方法是某個請求關聯的處理方法。
簡化版本
可能有人不是很理解前面的實際案例,這裡提供一個簡化的版本。
一、新建一個只帶Web的Spring Boot專案
二、定義一個介面
這個介面有一個方法,帶有@GetMapping註解。
public interface ControllerInterface { @GetMapping("/hello") String hello(); }
三、新增實現類
@RequestMapping @ResponseBody @Service public class ControllerInterfaceImpl implements ControllerInterface { @Override public String hello() { return "hello world"; } }
四、啟動並測試
啟動專案,訪問http://localhost:8080/hello
發現確實可以訪問。實際上組合方式還有很多,你可以把註解都寫在介面上。
@RequestMapping原理簡述
一、搜尋處理類
一個類上如果有@Controller或者@ReqeustMapping註解,會被認定為是請求的Handler。
二、搜尋處理方法
找到處理類後,第二步就是在處理類中查詢處理方法,即標註有@RequestMapping(或者其他變種)的方法,注意這裡掃描的過程中,會向上掃描父類或者介面是否帶有此註解。這個操作由HandlerMethodSelector來完成(Spring 4有這個類,後面的版本可能名稱有所變更)
三、整合URL生成RequestMappingInfo
如果處理類上有@RequestMpping註解,且有設定url,則會將類上和方法上的URL拼接起來。最終形成一個RequestMappingInfo。
四、生成對映關係
每個RequestMappingInfo會對映到一個處理方法HandlerMethod。