本篇內(nèi)容介紹了“RequestMapping要寫在Controller類里嗎”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
高郵ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!
使用Spring Cloud做項目的同學(xué)會使用Feign這個組件進(jìn)行遠(yuǎn)程服務(wù)的調(diào)用,F(xiàn)eign這個組件采用模板的方式,有著優(yōu)雅的代碼書寫規(guī)范。核心原理對Feign等相關(guān)注解進(jìn)行解析,并提取信息,在Spring Boot工程啟動時,通過反射生產(chǎn)Request的bean,并將提取的信息,設(shè)置到bean中,最后注入到ioc容器中。
現(xiàn)在有這樣的場景,服務(wù)A提高RestApi接口,服務(wù)B、C、D等服務(wù)需要調(diào)用服務(wù)A提供的RestApi接口,這時最常見的做法是在服務(wù)B、C、D分別寫一個FeignClient,并需要寫RestApi接口的接收參數(shù)的實體和接收響應(yīng)的實體DTo類。這樣的做法就是需要不停復(fù)制代碼。
有沒有辦法簡潔上面的操作呢?有一種最常見的做法是將將服務(wù)A進(jìn)行模塊拆分,將FeignClient和常見的model、dto對外輸出的類單獨寫一個模塊,可以類似于取名a-service-open_share。這樣將服務(wù)A服務(wù)分為兩個模塊,即A服務(wù)的業(yè)務(wù)模塊和A服務(wù)需要被其他服務(wù)引用的公共類的模塊。服務(wù)B、C、D只需要引用服務(wù)A的a-service-open_share就具備調(diào)用服務(wù)A的能力。
筆者在這里遇到一個有趣的其問題。首先看問題:
寫一個FeignClient:
@FeignClient(name = "user-service") public interface UserClient { @GetMapping("/users") ListgetUsers();
寫一個實現(xiàn)類:
@RestController public class UserController implements UserClient { @Autowired UserService userService; @OverRide ListgetUsers(){ return userService.getUsers(); }
啟動工程,瀏覽器訪問接口localhost:8008/users,竟然能正確訪問?!明明我在UserController類的getUsers方法沒有加RequestMapping這樣的注解。為何能正確的映射?!
帶著這樣的疑問,我進(jìn)行了一番的分析和探索!
首先就是自己寫了一個demo,首先創(chuàng)建一個接口類:
public interface ITest { @GetMapping("/test/hi") public String hi(); }
寫一個Controller類TestController
@RestController public class TestController implements ITest { @Override public String hi() { return "hi you !"; }
啟動工程,瀏覽器訪問:http://localhost:8762/test/hi,瀏覽器顯示:
hi you !
我去,TestController類的方法 hi()能夠得到ITest的方法hi()的 @GetMapping(“/test/hi”)注解嗎? 答案肯定是獲取不到的。
特意編譯了TestController字節(jié)碼文件:
javap -c TestController
public class com.example.demo.web.TestController implements com.example.demo.web.ITest { public com.example.demo.web.TestController(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return public java.lang.String hi(); Code: 0: ldc #2 // String hi you ! 2: areturn }
上面的字節(jié)碼沒有任何關(guān)于@GetMapping(“/test/hi”)的信息,可見TestController直接獲取不到@GetMapping(“/test/hi”)的信息。
那應(yīng)該是Spring MVC在啟動時在向容器注入Controller的Bean(HandlerAdapter)時做了處理。初步判斷應(yīng)該是通過反射獲取到這些信息,并組裝到Controller的Bean中。首先看通過反射能不能獲取ITest的注解信息:
public static void main(String[] args) throws ClassNotFoundException { Class c = Class.forName("com.example.demo.web.TestController"); Class[] i=c.getInterfaces(); System.out.println("start interfaces.." ); for(Class clz:i){ System.out.println(clz.getSimpleName()); Method[] methods = clz.getMethods(); for (Method method : methods) { if (method.isAnnotationPresent(GetMapping.class)) { GetMapping w = method.getAnnotation(GetMapping.class); System.out.println("value:" + w.value()[0] ); } } } System.out.println("end interfaces.." ); Method[] methods = c.getMethods(); for (Method method : methods) { if (method.isAnnotationPresent(GetMapping.class)) { GetMapping w = method.getAnnotation(GetMapping.class); System.out.println("value:" + w.value()); } } }
允運行上面的代碼:
start interfaces..
ITest
value:/test/hi
end interfaces..
可見通過反射是TestController類是可以獲取其實現(xiàn)的接口的注解信息的。為了驗證Spring Mvc 在注入Controller的bean時通過反射獲取了其實現(xiàn)的接口的注解信息,并作為urlMapping進(jìn)行了映射。于是查看了Spring Mvc 的源碼,經(jīng)過一系列的跟蹤在RequestMappingHandlerMapping.java類找到了以下的方法:
protected RequestMappingInfo getMappingForMethod(Method method, Class> handlerType) { RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { info = typeInfo.combine(info); } } return info; }
繼續(xù)跟蹤源碼在AnnotatedElementUtils 類的searchWithFindSemantics()方法中發(fā)現(xiàn)了如下代碼片段:
// Search on methods in interfaces declared locally Class>[] ifcs = method.getDeclaringClass().getInterfaces(); result = searchOnInterfaces(method, annotationType, annotationName, containerType, processor, visited, metaDepth, ifcs); if (result != null) { return result; }
這就是我要尋找的代碼片段,驗證了我的猜測。
“RequestMapping要寫在Controller類里嗎”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!