<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SringMVC從入門(mén)到源碼,這一篇就夠

          共 12778字,需瀏覽 26分鐘

           ·

          2020-09-15 07:27

          SpringMVC簡(jiǎn)介

          Java行業(yè)的誰(shuí)人不知SSM框架呢?除非你告訴我剛學(xué)Java,我就相信你不知道SpringMVC。

          關(guān)于SringMVC的由來(lái)和干嘛用的基本都不用介紹了,基本都知道了。但是有一點(diǎn)可以肯定的是:有很多人只停留在SpringMVC使用層面,對(duì)于SpringMVC的底層原理和源碼卻沒(méi)有深入了解過(guò)。

          這一期我們就來(lái)了解「SpringMVC的底層原理和源碼」,在以前的JSP時(shí)代,代碼中前端和后端都混在一起,可能比較老的程序員就寫(xiě)過(guò)下面的代碼,這就是大名鼎鼎的JSPServlet時(shí)代。

          在一些老的項(xiàng)目中可能就會(huì)出現(xiàn)這樣的代碼,這樣的代碼是不是看起來(lái)非常的帶勁,要是讓你維護(hù)這樣的代碼,想死的心都有。

          這樣的代碼前端和后端混在一起,相互依賴JSP與Java Bean之間嚴(yán)重耦合,java代碼和Html代碼混在一起,這要求開(kāi)發(fā)人員既要會(huì)前端也要會(huì)后端,給測(cè)試帶來(lái)了很多不方便,代碼也不能復(fù)用。

          諸如此類(lèi)的問(wèn)題,為了解決這樣的問(wèn)題,首先就是將這些代碼進(jìn)行嚴(yán)格的劃分,前端與后端的代碼分開(kāi),逐漸出現(xiàn)代碼的分層架構(gòu),各層職責(zé)分明。

          但是,這樣的模型層也還會(huì)有問(wèn)題,首先每個(gè)模塊就需要一個(gè)Servlet控制器,模塊多的,控制器就會(huì)變得很多,這樣會(huì)導(dǎo)致控制器復(fù)雜。

          并且更換視圖技術(shù)麻煩,嚴(yán)重依賴Servlet API。Java Bean結(jié)構(gòu)包含持久化層以及業(yè)務(wù)的處理,數(shù)據(jù)的封裝,這樣就會(huì)導(dǎo)致Java Bean結(jié)構(gòu)臃腫。

          按照我們現(xiàn)在代碼的分層,可以把Java Bean又分為「持久層(dao)和服務(wù)層(Service)」 以及我們的 「應(yīng)用控制層(Controller)」

          SpringMVC原理

          為了簡(jiǎn)化控制層(Servlet),在SpringMVC框架中使用「DispatcherServlet(前端控制器)」 調(diào)度我們自己的「應(yīng)用控制層(Controller)」。

          就這樣逐漸的演變,出現(xiàn)了我們現(xiàn)在真正意義上的Web MVC三層架構(gòu),具體的結(jié)構(gòu)圖如下所示:

          首先來(lái)說(shuō)明一下SpringMVC幾個(gè)核心的組件:

          1. DispatcherServlet:前端前端控制器主要負(fù)責(zé)調(diào)度工作,進(jìn)行全局的流程控制。比如:調(diào)度HandlerMapping然后返回執(zhí)行鏈。
          2. HandlerMapping:處理器映射器會(huì)返回一個(gè)執(zhí)行鏈,通俗來(lái)講也就是執(zhí)行的邏輯順序,執(zhí)行鏈中包含多個(gè)「Interceptor(攔截器)」 和一個(gè)「Handler(處理器)」。
          3. HandlerAdapter:處理器適配器里面包含了處理器的調(diào)用,使用適配器的設(shè)計(jì)原則,通過(guò)反射調(diào)用我們自己的Controller。
          4. Handler:處理器也就是我們的Controller,用戶對(duì)應(yīng)的請(qǐng)求URL請(qǐng)求過(guò)來(lái),通過(guò)請(qǐng)求與我們Controller的映射規(guī)則(HandlerMapping)相對(duì)應(yīng)起來(lái),這個(gè)就是處理器。
          5. ModelAndView:模型和視圖,模式(Model)也就是我們的數(shù)據(jù),通過(guò)上面反射調(diào)用Handler(Controller)生成的數(shù)據(jù),以及邏輯視圖(View)。邏輯視圖并不是真正的視圖名,它只是一個(gè)邏輯視圖名,比如:index。
          6. View:視圖,這時(shí)候才會(huì)通過(guò)上面生成的邏輯視圖名生成對(duì)應(yīng)的物理視圖,返回前端呈現(xiàn)用戶。

          Hello World

          上面說(shuō)了那么多,其實(shí)還是要在項(xiàng)目進(jìn)行實(shí)踐中才會(huì)有深刻的體會(huì),下面我們通過(guò)實(shí)際一個(gè)案例進(jìn)行上面的深刻的理解。

          這里我使用idea搭建SSM項(xiàng)目,還用Eclipse的同學(xué),建議你該換工具了,首先New - Project

          然后左邊選擇Maven,右邊勾選Create from archetype,并且選擇webapp模塊:

          下面就是填寫(xiě)一些GroupId以及ArtifactId,這些比較簡(jiǎn)單就直接跳過(guò)了,不然會(huì)被大佬diss死了,創(chuàng)建完項(xiàng)目后的基本目錄結(jié)構(gòu)如下:

          并且在resource目錄下分別創(chuàng)建下面四個(gè)配置文件「applicationContext.xml、jdbc.properties、log4j.properties、spring-mvc.xml」。

          applicationContext.xml是Spring的核心配置文件,內(nèi)容如下:

          "1.0"?encoding="UTF-8"?>
          "http://www.springframework.org/schema/beans"
          ???????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ???????xmlns:tx="http://www.springframework.org/schema/tx"?xmlns:context="http://www.springframework.org/schema/context"
          ???????xsi:schemaLocation="http://www.springframework.org/schema/beans
          ????????????????????????http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
          ????????????????????????http://www.springframework.org/schema/tx
          ????????????????????????http://www.springframework.org/schema/tx/spring-tx.xsd?http://www.springframework.org/schema/context?http://www.springframework.org/schema/context/spring-context.xsd"
          >

          ????
          ????"propertyConfigurer"?class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
          ????????"location"?value="classpath:jdbc.properties"/>
          ????

          ????
          ????"dataSource"?class="com.alibaba.druid.pool.DruidDataSource">
          ????????"driverClassName"?value="${driver}"/>
          ????????"url"?value="${url}"/>
          ????????"username"?value="${username}"/>
          ????????"password"?value="${password}"/>
          ????

          ????
          ????"sqlSessionFactory"?class="org.mybatis.spring.SqlSessionFactoryBean">
          ????????"dataSource"?ref="dataSource"/>
          ????????
          ????????"typeAliasesPackage"?value="com.ldc.model"/>
          ????????
          ????????"mapperLocations"?value="classpath:mapper/*.xml"/>
          ????

          ????
          ????"org.mybatis.spring.mapper.MapperScannerConfigurer">
          ????????
          ????????"sqlSessionFactoryBeanName"?value="sqlSessionFactory"/>
          ????????
          ????????"basePackage"?value="com.ldc.dao"/>
          ????

          ????
          ????"transactionManager"?class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          ????????"dataSource"?ref="dataSource"/>
          ????


          這個(gè)文件主要配置了數(shù)據(jù)源、數(shù)據(jù)庫(kù)的來(lái)連接的配置信息,數(shù)據(jù)的詳細(xì)信息就放在jdbc.properties中:

          driver=com.mysql.cj.jdbc.Driver
          url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
          username=root
          password=user
          initialSize=0
          maxActive=20
          maxIdle=20
          minIdle=1
          maxWait=60000

          這里的數(shù)據(jù)庫(kù)信息,你們只要修改數(shù)據(jù)庫(kù)的用戶名了密碼就行了,其它的作為測(cè)試信息基本就不用修改了。

          接下來(lái)就是日志的配置信息log4j.properties,這里只做簡(jiǎn)單的日志配置:

          #日志輸出級(jí)別
          log4j.rootLogger=debug,stdout,D,E

          #設(shè)置stdout的日志輸出控制臺(tái)
          log4j.appender.stdout=org.apache.log4j.ConsoleAppender
          #輸出日志到控制臺(tái)的方式,默認(rèn)為System.out
          log4j.appender.stdout.Target?=?System.out
          #設(shè)置使用靈活布局
          log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
          #靈活定義輸出格式
          log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd?HH:mm:ss,SSS}?-[%p]??method:[%c?(%rms)]?-?%m%n

          配置完日志信息后,接著配置spring-mvc.xml,這個(gè)的SpringMVC框架內(nèi)的信息配置文件:

          "1.0"?encoding="UTF-8"?>
          "http://www.springframework.org/schema/beans"
          ???????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ???????xmlns:context="http://www.springframework.org/schema/context"
          ???????xmlns:mvc="http://www.springframework.org/schema/mvc"
          ???????xsi:schemaLocation="http://www.springframework.org/schema/beans
          ???????http://www.springframework.org/schema/beans/spring-beans.xsd
          ???????http://www.springframework.org/schema/context
          ???????http://www.springframework.org/schema/context/spring-context.xsd
          ???????http://www.springframework.org/schema/mvc
          ???????http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
          >

          ????
          ????"com.ldc"/>

          ????
          ????

          ????
          ????
          ?
          ?
          ????"org.springframework.web.servlet.view.InternalResourceViewResolver">
          ????????"viewClass"?value="org.springframework.web.servlet.view.JstlView"/>
          ????????"prefix"?value="/WEB-INF/jsp/"/>
          ????????"suffix"?value=".jsp"/>
          ????

          這和配置信息也很簡(jiǎn)單,主要包括「開(kāi)啟注解驅(qū)動(dòng)、包掃描、視圖解析器的配置」。

          配置完SpringMVC后,最后就是配置web.xml,web.xml是前端請(qǐng)求的入口文件:

          "http://xmlns.jcp.org/xml/ns/javaee"
          ?????????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ?????????xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee?http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
          ?????????version="3.1">

          ??mvcDemo
          ??
          ??
          ????index.jsp
          ??


          ??
          ??
          ????org.springframework.web.context.ContextLoaderListener
          ??


          ??
          ??
          ????contextConfigLocation
          ????classpath:applicationContext.xml
          ??


          ??
          ??
          ????CharacterEncodingFilter
          ????org.springframework.web.filter.CharacterEncodingFilter
          ????
          ??????encoding
          ??????utf-8
          ????

          ????
          ??????forceEncoding
          ??????true
          ????

          ??

          ??
          ????CharacterEncodingFilter
          ????/*
          ??

          ??
          ??
          ????springmvc
          ????org.springframework.web.servlet.DispatcherServlet
          ????
          ????
          ??????contextConfigLocation
          ??????classpath:spring-mvc.xml
          ????

          ????1
          ????true
          ??

          ??
          ????springmvc
          ????/
          ??


          在web.xml中主要包含:「默認(rèn)歡迎頁(yè)面的配置、字符編碼過(guò)濾器的配置、前端控制器、以及指定spring核心配置文件和SpringMVC的配置文件」

          以上就是最基本的配置,其它的配置信息一般是按需配置,這樣配置完后,我們搭建一個(gè)簡(jiǎn)單的SSM的項(xiàng)目基本已經(jīng)完成了。

          最后的Maven的坐標(biāo)依賴,如下:

          "1.0"?encoding="UTF-8"?>
          "http://maven.apache.org/POM/4.0.0"?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          ?????????xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?http://maven.apache.org/xsd/maven-4.0.0.xsd">
          ????4.0.0

          ????com.ldc
          ????mvcDemo
          ????1.0-SNAPSHOT
          ????war

          ????mvcDemo?Maven?Webapp

          ????
          ????
          ????????4.0.2.RELEASE
          ????????3.2.8
          ????????1.7.12
          ????????1.2.17
          ????????1.0.9
          ????

          ????
          ????
          ????????
          ????????
          ????????????junit
          ????????????junit
          ????????????4.11
          ????????????
          ????????????test
          ????????


          ????????
          ????????
          ????????????org.springframework
          ????????????spring-test
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-core
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-oxm
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-tx
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-jdbc
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-aop
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-context
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-context-support
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-expression
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-orm
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-web
          ????????????${srping.version}
          ????????

          ????????
          ????????????org.springframework
          ????????????spring-webmvc
          ????????????${srping.version}
          ????????

          ????????
          ????????
          ????????
          ????????????org.mybatis
          ????????????mybatis
          ????????????${mybatis.version}
          ????????

          ????????
          ????????????org.mybatis
          ????????????mybatis-spring
          ????????????1.2.2
          ????????

          ????????
          ????????
          ????????
          ????????????mysql
          ????????????mysql-connector-java
          ????????????5.1.35
          ????????

          ????????
          ????????
          ????????????commons-dbcp
          ????????????commons-dbcp
          ????????????1.4
          ????????

          ????????
          ????????
          ????????????jstl
          ????????????jstl
          ????????????1.2
          ????????

          ????????
          ????????
          ????????????log4j
          ????????????log4j
          ????????????${log4j.version}
          ????????

          ????????
          ????????????org.slf4j
          ????????????slf4j-api
          ????????????${slf4j.version}
          ????????

          ????????
          ????????????org.slf4j
          ????????????slf4j-log4j12
          ????????????${slf4j.version}
          ????????

          ????????
          ????????
          ????????????com.alibaba
          ????????????druid
          ????????????${druid.version}
          ????????

          ????


          ????
          ????????
          ????????
          ????????????
          ????????????????org.apache.maven.plugins
          ????????????????maven-compiler-plugin
          ????????????????3.2
          ????????????????
          ????????????????????<source>1.8source>
          ????????????????????1.8
          ????????????????????UTF-8
          ????????????????

          ????????????

          ????????

          ????


          maven做表中主要開(kāi)發(fā)包含的依賴數(shù)據(jù)庫(kù)驅(qū)動(dòng)、日志、mybaties、spring坐標(biāo)、web mvc的坐標(biāo)、以及繼承JSP的坐標(biāo)。

          這里前端技術(shù)可以繼承你們自己想要的:Freemarker或者Thymeleaf,只需要引入相關(guān)的Maven坐標(biāo),因?yàn)镴SP已經(jīng)基本被淘汰了,這里只是為了作測(cè)試,并不關(guān)心前端用什么技術(shù)。

          我們?cè)赾ontroller包下創(chuàng)建我們自己的測(cè)試類(lèi):UserController

          @Controller
          @RequestMapping("/user")
          public?class?UserController?{

          ????@Autowired
          ????private?IUserService?userService;

          ????@RequestMapping("/getUserById")
          ????public?ModelAndView?selectUser(@PathVariable("id")?Long?id)?throws?Exception?{
          ????????ModelAndView?mv?=?new?ModelAndView();
          ????????User?user?=?userService.selectUser(id);
          ????????mv.addObject("user",?user);
          ????????mv.setViewName("user");
          ????????return?mv;
          ????}
          }

          這里簡(jiǎn)單解釋一下:

          1. @Controller:標(biāo)名它是一個(gè)控制器,被Spring容器所管理,這個(gè)注解是在@Component后面出的,為了表示代碼的分層,于是就有了@Controller、@Service、@Mapper這三個(gè)注解,他們的作用是一樣的。
          2. @RequestMapping:表示接受的請(qǐng)求,還是GetMapping、PostMapping等注解表示請(qǐng)求方法的不同。
          3. @Autowired:表示自動(dòng)注入,前提就是被注入的對(duì)象被Spring容器所管理。
          4. ModelAndView:這個(gè)前面說(shuō)過(guò),它裝的就是數(shù)據(jù)和邏輯視圖名。

          這些還是比較簡(jiǎn)單的,通過(guò)下面配置Tomcat信息進(jìn)行部署,就可以啟動(dòng)項(xiàng)目進(jìn)行測(cè)試了:

          DispatcherServlet源碼解析

          這個(gè)還是比較簡(jiǎn)單的,還不會(huì)可以自行百度,啟動(dòng)項(xiàng)目后我們來(lái)測(cè)試一下前面,出現(xiàn)下面的界面說(shuō)明,你搭建SSM項(xiàng)目的基本環(huán)境已經(jīng)成功了:

          那么我們的前端請(qǐng)求是怎么一步一步的從「前臺(tái)->后臺(tái)->前臺(tái)」的呢?其實(shí)前面我們已經(jīng)說(shuō)了SpringMVC的基本原理,在這個(gè)基本原理的基礎(chǔ)上,從源碼的角度,進(jìn)行詳細(xì)的解析:

          上面說(shuō)到SpringMVC的核心調(diào)度器就是DispatcherServlet,負(fù)責(zé)主流程的調(diào)度工作,在DispatcherServlet里面最主要的方法就是doDispatch

          protected?void?doDispatch(HttpServletRequest?request,?HttpServletResponse?response)?throws?Exception?{??
          ????????HttpServletRequest?processedRequest?=?request;??
          ????????HandlerExecutionChain?mappedHandler?=?null;??
          ????????int?interceptorIndex?=?-1;??
          ??
          ????????try?{??
          ????????????ModelAndView?mv;??
          ????????????boolean?errorView?=?false;??
          ??
          ????????????try?{??
          ???????????????????//檢查是否是請(qǐng)求是否是multipart(如文件上傳),如果是將通過(guò)MultipartResolver解析??
          ????????????????processedRequest?=?checkMultipart(request);??
          ???????????????????//步驟2、請(qǐng)求到處理器(頁(yè)面控制器)的映射,通過(guò)HandlerMapping進(jìn)行映射??
          ????????????????mappedHandler?=?getHandler(processedRequest,?false);??
          ????????????????if?(mappedHandler?==?null?||?mappedHandler.getHandler()?==?null)?{??
          ????????????????????noHandlerFound(processedRequest,?response);??
          ????????????????????return;??
          ????????????????}??
          ???????????????????//步驟3、處理器適配,即將我們的處理器包裝成相應(yīng)的適配器(從而支持多種類(lèi)型的處理器)??
          ????????????????HandlerAdapter?ha?=?getHandlerAdapter(mappedHandler.getHandler());??
          ??
          ??????????????????//?304?Not?Modified緩存支持??
          ????????????????//此處省略具體代碼??
          ??
          ????????????????//?執(zhí)行處理器相關(guān)的攔截器的預(yù)處理(HandlerInterceptor.preHandle)??
          ????????????????//此處省略具體代碼??
          ??
          ????????????????//?步驟4、由適配器執(zhí)行處理器(調(diào)用處理器相應(yīng)功能處理方法)??
          ????????????????mv?=?ha.handle(processedRequest,?response,?mappedHandler.getHandler());??
          ??
          ????????????????//?Do?we?need?view?name?translation???
          ????????????????if?(mv?!=?null?&&?!mv.hasView())?{??
          ????????????????????mv.setViewName(getDefaultViewName(request));??
          ????????????????}??
          ??
          ????????????????//?執(zhí)行處理器相關(guān)的攔截器的后處理(HandlerInterceptor.postHandle)??
          ????????????????//此處省略具體代碼??
          ????????????}??
          ????????????catch?(ModelAndViewDefiningException?ex)?{??
          ????????????????logger.debug("ModelAndViewDefiningException?encountered",?ex);??
          ????????????????mv?=?ex.getModelAndView();??
          ????????????}??
          ????????????catch?(Exception?ex)?{??
          ????????????????Object?handler?=?(mappedHandler?!=?null???mappedHandler.getHandler()?:?null);??
          ????????????????mv?=?processHandlerException(processedRequest,?response,?handler,?ex);??
          ????????????????errorView?=?(mv?!=?null);??
          ????????????}??
          ??
          ????????????//步驟5?步驟6、解析視圖并進(jìn)行視圖的渲染??
          //步驟5?由ViewResolver解析View(viewResolver.resolveViewName(viewName,?locale))??
          //步驟6?視圖在渲染時(shí)會(huì)把Model傳入(view.render(mv.getModelInternal(),?request,?response);)??
          ????????????if?(mv?!=?null?&&?!mv.wasCleared())?{??
          ????????????????render(mv,?processedRequest,?response);??
          ????????????????if?(errorView)?{??
          ????????????????????WebUtils.clearErrorRequestAttributes(request);??
          ????????????????}??
          ????????????}??
          ????????????else?{??
          ????????????????if?(logger.isDebugEnabled())?{??
          ????????????????????logger.debug("Null?ModelAndView?returned?to?DispatcherServlet?with?name?'"?+?getServletName()?+??
          ????????????????????????????"':?assuming?HandlerAdapter?completed?request?handling");??
          ????????????????}??
          ????????????}??
          ??
          ????????????//?執(zhí)行處理器相關(guān)的攔截器的完成后處理(HandlerInterceptor.afterCompletion)??
          ????????????//此處省略具體代碼??
          ??
          ????????catch?(Exception?ex)?{??
          ????????????//?Trigger?after-completion?for?thrown?exception.??
          ????????????triggerAfterCompletion(mappedHandler,?interceptorIndex,?processedRequest,?response,?ex);??
          ????????????throw?ex;??
          ????????}??
          ????????catch?(Error?err)?{??
          ????????????ServletException?ex?=?new?NestedServletException("Handler?processing?failed",?err);??
          ????????????//?Trigger?after-completion?for?thrown?exception.??
          ????????????triggerAfterCompletion(mappedHandler,?interceptorIndex,?processedRequest,?response,?ex);??
          ????????????throw?ex;??
          ????????}??
          ??
          ????????finally?{??
          ????????????//?Clean?up?any?resources?used?by?a?multipart?request.??
          ????????????if?(processedRequest?!=?request)?{??
          ????????????????cleanupMultipart(processedRequest);??
          ????????????}??
          ????????}??
          ????}??

          這個(gè)方法不長(zhǎng),基本就是負(fù)責(zé)其它方法的調(diào)用,從我們上面分析到前端請(qǐng)求第一步到達(dá)SpringMVC后調(diào)用HandlerMapping(處理器映射器)返回執(zhí)行鏈HandlerExecutionChain

          我們debug啟動(dòng)項(xiàng)目,打個(gè)斷點(diǎn)看看,這個(gè)HandlerExecutionChain到底是個(gè)什么東西。

          我們可以看到,當(dāng)斷點(diǎn)執(zhí)行到HandlerExecutionChain后,查看HandlerExecutionChain中的handler其實(shí)就是我們自己的請(qǐng)求訪問(wèn)的Controller,比如上面的我們請(qǐng)求登陸操作,handler里面的信息就是我們自己的LoginController。

          同時(shí)包含LoginController的BeanType,前端要請(qǐng)求的方法,以及參數(shù)這個(gè)元數(shù)據(jù)信息,簡(jiǎn)單的概括就是:「HandlerExecutionChain里面handler就是我們要請(qǐng)求的Controller以及和一些interceptors信息」

          那么在獲取到這個(gè)HandlerExecutionChain之前肯定是有初始化所有的Spring容器中的Bean以及所有的url與Bean對(duì)應(yīng)的HandlerMapping對(duì)象。

          這個(gè)都是在Spring中去完成的,這個(gè)我們后面在做了解,我們?cè)龠M(jìn)一步的了解HandlerMapping對(duì)象存儲(chǔ)的內(nèi)容,再getHandler方法里面進(jìn)行打斷點(diǎn):

          handlerMapping是一個(gè)List對(duì)象,里面主要是這七個(gè)成員信息,我們比較熟悉的就是BeanNameUrlMappingSimpleUrlHandlerMapping對(duì)象,這些里面可以看出「handlerMapping主要存儲(chǔ)的各種映射規(guī)則」,通過(guò)beanName或者url映射到對(duì)應(yīng)的Bean對(duì)象。

          繼續(xù)往里面看,可以看到這里有個(gè)applicationContext對(duì)象,這個(gè)也就我們的上下文,里面還有beanFactory,也就是Spring管理的Bean對(duì)象都在這個(gè)工廠里面,包括Spring自己的和我們自己定義Bean信息。

          這個(gè)就是HandlerMapping對(duì)象,主要「包含著的Bean映射規(guī)則、Bean詳細(xì)信息?!?/strong>

          從HandlerMapping->HandlerExecutionChain的過(guò)程,用一句通俗易懂的話概括就是:「從茫茫的人海中找到了你(從beanFactory找到了請(qǐng)求對(duì)應(yīng)的Controller以及方法)」。

          當(dāng)獲取完我們的執(zhí)行鏈后,接著就是獲取我們的「處理器適配器」HandlerAdapter),

          getHandlerAdapter的方法中可以看到,根據(jù)返回的handlerMapping對(duì)象中的handler對(duì)象來(lái)獲取對(duì)應(yīng)的HandlerAdapter對(duì)象,直接返回。

          返回HandlerAdapter對(duì)象后,通過(guò)執(zhí)行HandlerAdapterhandle方法獲取ModelAndView對(duì)象,從這個(gè)方法的上面的注釋來(lái)看:Actually invoke the handler.。

          實(shí)際就是通過(guò)「反射」的方式動(dòng)態(tài)的執(zhí)行我們自己的Controller中的方法,也就是前端請(qǐng)求的Controller,因?yàn)?code style="word-wrap: break-word;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(53, 148, 247);background: rgba(59, 170, 250, 0.1);padding-right: 2px;padding-left: 2px;border-radius: 2px;height: 21px;line-height: 22px;">mappedHandler.getHandler()返回的「handler對(duì)象包含著請(qǐng)求Controller的詳細(xì)信息,包括全類(lèi)名」。

          獲取到ModelAndView之后,接著就執(zhí)行我們的攔截器的后置處理方法postHandle

          從他的源碼可以看出,它是獲取到所有的攔截器,然后一個(gè)一個(gè)遍歷,執(zhí)行。

          執(zhí)行完所有攔截器的后置處理方法,就是最后?視圖的渲染,這里執(zhí)行的是processDispatchResult方法,并把ModelAndView對(duì)象作為參數(shù)傳遞進(jìn)去。

          processDispatchResult方法里面最重要的就是render方法了,執(zhí)行視圖的渲染,最后將渲染的結(jié)果呈現(xiàn)給用戶。

          到這里DispatcherServlet主要執(zhí)行邏輯就講完了,其實(shí)主要講的還是SpringMVC的從前端請(qǐng)求->后臺(tái)->前端這樣的一個(gè)過(guò)程,限于篇幅,從源碼的角度大概講解這個(gè)的過(guò)程是怎么跑起來(lái)的。

          一篇文章要把SpringMVC的都講清楚是不可能的,SpringMVC所有講下來(lái),都能寫(xiě)一本書(shū)了,后續(xù)的源碼我們繼續(xù)精進(jìn),這篇作為一個(gè)大體脈絡(luò)的了解。


          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲深喉口爆 | 日B视频在线观看 | 超碰在线伊人 | 一级做a在线观看 | 一区二区三区AV |