javascript
springmvc是什么_当一个http请求来临时,SpringMVC究竟偷偷帮你做了什么?
前文
Spring MVC是一個基于Java的實現(xiàn)了MVC設(shè)計模式的請求驅(qū)動類型的輕量級Web框架,通過把Model,View,Controller分離,將web層進行職責(zé)解耦,把復(fù)雜的web應(yīng)用分成邏輯清晰的幾部分,簡化開發(fā),減少出錯,方便組內(nèi)開發(fā)人員之間的配合。
Springmvc的優(yōu)點:
請求映射器源碼解析
這些優(yōu)秀的特性使得它在企業(yè)級開發(fā)中使用率超過98%,如此優(yōu)秀的框架,你是否疑惑過,在一個請求到達后,是如何被SpringMvc攔截到并處理的?
相信大家對上面的流程圖都很熟悉,或多或少無論是在準備面試的時候,還是自己學(xué)習(xí)的時候,都會接觸到這個流程圖,我見過很多的人,對著這個圖死記硬背!我也面試過一些技術(shù)人員,問到這塊知識,仰著頭閉著眼(夸張一下)把這塊知識說出來,再往深了問一點就懵逼,歸根到底就是對框架理解不夠深刻。
SpringMVC是如何感知到每個方法對應(yīng)的url路徑的?
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping 實現(xiàn) org.springframework.beans.factory.InitializingBean 覆蓋 afterPropertiesSet方法,這個方法會在Spring容器初始化的時候回調(diào)該方法該方法類定義為@Override public void afterPropertiesSet() {initHandlerMethods(); } 復(fù)制代碼調(diào)用initHandlerMethods方法,那么initHandlerMethods里面干了什么事情呢?對該方法逐步分析!/*** Scan beans in the ApplicationContext, detect and register handler methods.* @see #getCandidateBeanNames()* @see #processCandidateBean* @see #handlerMethodsInitialized*/ protected void initHandlerMethods() {for (String beanName : getCandidateBeanNames()) {if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {processCandidateBean(beanName);}}handlerMethodsInitialized(getHandlerMethods()); }首先 getCandidateBeanNames() 方法,我們看它的定義/*** Determine the names of candidate beans in the application context.* @since 5.1* @see #setDetectHandlerMethodsInAncestorContexts* @see BeanFactoryUtils#beanNamesForTypeIncludingAncestors*/ protected String[] getCandidateBeanNames() {return (this.detectHandlerMethodsInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(obtainApplicationContext(), Object.class) :obtainApplicationContext().getBeanNamesForType(Object.class)); }- 這個方法本質(zhì)的目的就是為了從bean容器中,獲取所有的bean,為什么是獲取全部的 因為它是基于Object.class類型來獲取的類,故而是全部的類,但是這個方法其實深究起來,知識點很多,因為它涉及到Spring父子容器的知識點,所以我決定,后面花一篇文檔單獨去講,這里你只需要知道,這個方法可以獲取Spring容器里面所有的bean然后返回!
- beanType = obtainApplicationContext().getType(beanName); 這個方法是基于bean名稱獲取該類的Class對象
- isHandler(beanType) 這個方法是判斷該類是是加注了Controller注解或者RequestMapping
- detectHandlerMethods(Object handler)
內(nèi)部該段邏輯可以遍歷某個類下所有的方法
- getMappingForMethod(method, userType); 這個方法的內(nèi)部做了什么呢? 該i方內(nèi)部讀取所有的映射方法的所有定義,具體的邏輯如下
- getPathPrefix(handlerType); 該方法是處理方法前綴,如果存在和前者方法級別的合并
- 最終返回一個方法與方法描述信息的map映射集合(Map<Method, RequestMappingInfo>),循環(huán)遍歷該集合! Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);找到該方法的代理方法! registerHandlerMethod(handler, invocableMethod, mapping);注冊該方法! 我們深入該方法摒棄其他與本文無關(guān)的代碼,會發(fā)現(xiàn)這么一段代碼!
會發(fā)現(xiàn),我們方法上標注的 url會和前面讀取的該方法的定義綁定在一個叫做 urlLookup的方法里面,請大家記住這個方法,這個方法對我們理解SpringMvc的處理邏輯有大用處!
3.請求獲取邏輯源碼解析
現(xiàn)在,整個工程所有對應(yīng)的@requestMapping的方法已經(jīng)被緩存,以該方法為例子!@RestController public class TestController {@RequestMapping("test")public String test(){return "success";} }現(xiàn)在在urlLookup屬性里面就有一個 key為test,value為test()方法詳細定義的 k:v鍵值對:v:
我們看下下面這個類圖,DispatcherServlet這個關(guān)鍵的中央類,實際上是Servlet的子類,熟悉Servlet的同學(xué)都知道,之前在做Servlet開發(fā)的時候,所有的請求經(jīng)過配置后都會被內(nèi)部的doget和dopost方法攔截,至此SpringMvc為什么能夠攔截URL也就不難分析了,攔截到url后,進入如下的流程調(diào)用鏈!
請求經(jīng)由 org.springframework.web.servlet.FrameworkServlet#doGet捕獲,委托給org.springframework.web.servlet.FrameworkServlet#processRequest方法,最后在調(diào)用org.springframework.web.servlet.DispatcherServlet#doService來處理真正的邏輯!我們看一下這個方法里面的一些主要邏輯吧!
org.springframework.web.servlet.DispatcherServlet#doDispatch調(diào)用org.springframework.web.servlet.DispatcherServlet#getHandler方法,再次調(diào)用org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler經(jīng)由org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal方法的org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#lookupHandlerMethod的org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#getMappingsByUrl講過這么長的調(diào)用鏈是不是懵了,此時我們終于看到了正主!
/*** Return matches for the given URL path. Not thread-safe.* @see #acquireReadLock()*/ @Nullable public List<T> getMappingsByUrl(String urlPath) {return this.urlLookup.get(urlPath); }這段代碼是不是熟悉?這就是我們Spring容器在初始化的時候?qū)rl和方法定義放置的那個屬性,現(xiàn)在Spring容器經(jīng)由DispatcherServlet攔截請求后又重新找到該方法,并且返回!此時就完成了MVC流程圖里面的HandlerMapping處理映射器的部分!
本章關(guān)于請求映射器的源碼分析到這也就結(jié)束了,后續(xù)作者會將處理適配器,處理器,視圖解析器一一講明白,其實后續(xù)的邏輯也就很簡單了,簡單來說,拿到方法后反射執(zhí)行該方法(不一定,一般場景是這樣),然后拿到返回值,判斷是否有@responseBody注解,判斷是否需要轉(zhuǎn)換成json,再通過write寫回到頁面!大致流程就是這樣,詳細過程作者后續(xù)會寫!
經(jīng)過今天的流程分析,你能否基于Servlet寫一個屬于自己的SpringMvc呢?
總結(jié)
以上是生活随笔為你收集整理的springmvc是什么_当一个http请求来临时,SpringMVC究竟偷偷帮你做了什么?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python输出文本和值_python读
- 下一篇: @configurationproper