日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

springmvc是什么_当一个http请求来临时,SpringMVC究竟偷偷帮你做了什么?

發(fā)布時間:2023/12/2 javascript 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springmvc是什么_当一个http请求来临时,SpringMVC究竟偷偷帮你做了什么? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前文

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)點:

  • 可以支持各種視圖技術(shù),而不僅僅局限于JSP;
  • 與Spring框架集成(如IoC容器、AOP等);
  • 清晰的角色分配:前端控制器(dispatcherServlet) , 請求到處理器映射(handlerMapping), 處理器適配器(HandlerAdapter), 視圖解析器(ViewResolver)。
  • 支持各種請求資源的映射策略。
  • 請求映射器源碼解析

    這些優(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然后返回!
    initHandlerMethods() 獲取到所有的bean之后然后循環(huán)遍歷,我們將目光聚集在循環(huán)體內(nèi)部的processCandidateBean方法protected void processCandidateBean(String beanName) {Class<?> beanType = null;try {beanType = obtainApplicationContext().getType(beanName);}catch (Throwable ex) {// An unresolvable bean type, probably from a lazy bean - let's ignore it.if (logger.isTraceEnabled()) {logger.trace("Could not resolve type for bean '" + beanName + "'", ex);}}if (beanType != null && isHandler(beanType)) {detectHandlerMethods(beanName);} }
    • beanType = obtainApplicationContext().getType(beanName); 這個方法是基于bean名稱獲取該類的Class對象
    • isHandler(beanType) 這個方法是判斷該類是是加注了Controller注解或者RequestMapping
    @Override protected boolean isHandler(Class<?> beanType) {return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
    • detectHandlerMethods(Object handler)
    Map<Method, T> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> {try {return getMappingForMethod(method, userType);}catch (Throwable ex) {throw new IllegalStateException("Invalid mapping on handler class [" +userType.getName() + "]: " + method, ex);}});

    內(nèi)部該段邏輯可以遍歷某個類下所有的方法

    • getMappingForMethod(method, userType); 這個方法的內(nèi)部做了什么呢? 該i方內(nèi)部讀取所有的映射方法的所有定義,具體的邏輯如下

    設(shè)置了該方法 的映射路徑,方法對象,方法參數(shù),設(shè)置的方法請求頭,消費類型,可接受類型,映射名稱等信息封裝成RequestMappingInfo對象返回!
    • 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)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。