爱上源码,重学Spring MVC深入

[复制链接]
发表于 2022-11-2 13:59:59 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1.1 gradle搭建源码调试环境

1)搭建gradle环境

4个步骤
1、File-New-Module
选择java和web

2、填写包信息

3、存储路径

2)增加起步依赖

依赖的项目,直接复制粘贴上去
1、对spring的依赖
2、对MVC的依赖
3、对Tomcat插件的依赖
build.gradle
  1. group 'com.spring.test'
  2. version '5.0.2.RELEASE'
  3. apply plugin: 'java'
  4. apply plugin: 'war'
  5. apply plugin: 'com.bmuschko.tomcat' //tomcat: 插件
  6. // tomcat: 以下配置会在第一次启动时下载插件二进制文件
  7. //在项目根目录中执行gradle tomcatRun
  8. buildscript {
  9.     repositories {
  10.         jcenter()
  11.     }
  12.     dependencies {
  13.         classpath 'com.bmuschko:gradle-tomcat-plugin:2.5'
  14.     }
  15. }
  16. // 配置阿里源
  17. allprojects {
  18.     repositories {
  19.         maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
  20.     }
  21. }
  22. dependencies {
  23.     testCompile group: 'org.testng', name: 'testng', version: '6.14.3'
  24.     runtime 'javax.servlet:jstl:1.1.2' // Servlet容器必需
  25.     compile(project(':spring-context'))
  26.     compile(project(':spring-web'))
  27.     compile(project(':spring-webmvc'))
  28.     // tomcat: 将Tomcat运行时库添加到配置tomcat中: (此处为Tomcat9)
  29.     def tomcatVersion = '9.0.1'
  30.     tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
  31.             "org.apache.tomcat.embed:tomcat-embed-logging-juli:9.0.0.M6",
  32.             "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
  33. }
  34. // tomcat: 一些协议设置(注意,这里必须加上,不然会抛tomcat的异常,仅限tomcat9)
  35. tomcat {
  36.     httpProtocol = 'org.apache.coyote.http11.Http11Nio2Protocol'
  37.     ajpProtocol  = 'org.apache.coyote.ajp.AjpNio2Protocol'
  38. }
  39. // UTF-8
  40. tasks.withType(JavaCompile) {
  41.     options.encoding = "UTF-8"
  42. }
复制代码
3)MVC代码编写

前提:
增加WEB-INF目录和Web.xml
1、打开File  -  Proect Structrue
2、选中刚才的mvc项目,展开,选中web gradle , 到右边 点击加号
3、确认路径
spring-mvc-test\src\main\webapp\WEB-INF\web.xml
WEB-INF和xml创建完毕

webapp/WEB-INF/web.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5.          version="4.0">
  6.        
  7.         <servlet>
  8.                 <servlet-name>mvc</servlet-name>
  9.                 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  10.                 <init-param>
  11.                         <param-name>contextConfigLocation</param-name>
  12.                         <param-value>classpath:mvc-servlet.xml</param-value>
  13.                        
  14.                 </init-param>
  15.                
  16.                 <load-on-startup>1</load-on-startup>
  17.         </servlet>
  18.         <servlet-mapping>
  19.                 <servlet-name>mvc</servlet-name>
  20.                 <url-pattern>/</url-pattern>
  21.         </servlet-mapping>
  22. </web-app>
复制代码
resources/mvc-servlet.xml
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.            xmlns:mvc="http://www.springframework.org/schema/mvc"
  3.            xmlns:context="http://www.springframework.org/schema/context"
  4.            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.            xsi:schemaLocation="
  6.         http://www.springframework.org/schema/beans
  7.         http://www.springframework.org/schema/beans/spring-beans.xsd
  8.         http://www.springframework.org/schema/mvc
  9.         http://www.springframework.org/schema/mvc/spring-mvc.xsd
  10.         http://www.springframework.org/schema/context
  11.         http://www.springframework.org/schema/context/spring-context.xsd">
  12.        
  13.         <context:component-scan base-package="com.spring.mvc.test"/>
  14.        
  15.         <bean id="internalResourceViewResolver" >
  16.                 <property name="prefix" value="/"/>
  17.                
  18.                 <property name="suffix" value=".jsp"/>
  19.         </bean>
  20.        
  21.         <mvc:annotation-driven/>
  22.        
  23.         <mvc:default-servlet-handler/>
  24. </beans>
复制代码
webapp/index.jsp
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3.   <head>
  4.     <title>SpringMvc源码深入剖析</title>
  5.   </head>
  6.   <body>
  7.   Gradle构建Spring MVC例子....
  8.   </body>
  9. </html>
复制代码
MvcController.java
  1. package com.spring.mvc.test;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.ResponseBody;
  5. import org.springframework.web.servlet.ModelAndView;
  6. @Controller
  7. public class MvcController {
  8.         @RequestMapping("/index")
  9.         public ModelAndView getModeAndView() {
  10.                 //创建一个模型视图对象
  11.                 ModelAndView mav = new ModelAndView("index");
  12.                 return mav;
  13.         }
  14.         @RequestMapping("/text")
  15.         @ResponseBody
  16.         public String text() {
  17.                 return "Text...";
  18.         }
  19. }
复制代码
4)启动MVC项目

两种启动方式
方式一:外挂启动
idea环境外面启动(项目根目录下运行 gradle + task name)
Task NameDepends OnTypeDescriptiontomcatRun-TomcatRun启动Tomcat实例并将Web应用程序部署到该实例。tomcatRunWar-TomcatRunWar启动Tomcat实例并将WAR部署tomcatStop-TomcatStop停止Tomcat实例tomcatJasper-TomcatJasper运行JSP编译器并使用Jasper将JSP页面转换为Java源代码。在项目根目录中执行gradle tomcatRun
  1. #动Tomcat实例并将Web应用程序部署到该实例
  2. gradle  tomcatRun
  3. #停止Tomcat实例
  4. gradle tomcatStop
复制代码
控制台正常输出

方式二:集成到idea中启动

设置

即可点击运行

运行成功

方式三:
idea右边找到gradle的task,直接双击,这个爽~

访问MVC项目
注意:spring-test-mvc是项目的名称
  1. http://localhost:8080/spring-test-mvc/index
复制代码
效果如下

5)源码调试配置

idea里的调试
简单,debug模式启动tomcat即可

远程调试模式
重要
想要远程debug,需要使用上面的方法二,因为debug启动需要设置gradle的环境变量,
即运行gradle命令的时候插入一些参数命令。
增加debug参数,对外暴露5005端口,即监听5005端口。
  1. -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
复制代码

在配置Remote;监听5005端口
点击+号,创建Remote;默认配置即可

最后一步
1、先运行tomcat
2、再运行remote
  1. http://localhost:8080/spring-test-mvc/index
复制代码
打上断点试试!
包括我们之前ioc里的bean创建等地方,随便打。
1.2 MVC工作原理和继承关系

1)MVC底层工作原理

目标:认识SpringMVC的工作原理(对照源码),如何找到对应的Controller,进行页面渲染的
步骤:11步
源头:http://localhost:8080/spring-test-mvc/index

SpringMVC工作原理
1、DispatcherServlet(前端控制器) 是个servlet,负责接收Request 并将Request 转发给对应的处理组件。
2、 HanlerMapping (处理器映射器)是SpringMVC 中完成url 到Controller 映射的组件。DispatcherServlet 从HandlerMapping 查找处理Request 的Controller,
3、HanlerMapping 返回一个执行器链(url 到Controller 映射的组件)给DispatcherServlet
4、DispatcherServlet请求处理器适配器HandlerAdapter
5、处理器适配器HandlerAdapter去访问我们的handler(controller)
6、handler(controller)返回ModelAndView给处理器适配器HandlerAdapter
7、处理器适配器HandlerAdapter返回ModelAndView给DispatcherServlet
8、DispatcherServlet请求ViewResolver视图解析器
9、ViewResolver视图解析器返回view给DispatcherServlet
10、DispatcherServlet请求view做页面解析和渲染
11、view将渲染好的数据返回给DS,DS将渲染好的字符流给client,看到了页面!
2)MVC核心类继承关系

目标:简单认识MVC的继承关系
tips
不要求记住

DispatcherServlet   前端总控制器(webmvc源码)
FrameworkServlet  (webmvc源码)
HttpServletBean  是的一个简单扩展类((webmvc源码)
HttpServlet(servlet API , 已经离开了spring mvc的控制范围)
1.3 Spring MVC源码深入剖析
  1. 引言:
  2. 当前源码讲解思路
  3. 1、断点调试
  4. 2、流程图对照
  5. 3、继承关系对照
复制代码
1.3.1 MVC启动阶段

注意,这个阶段没法debug,我们从servlet规范去直接看源码
下面的请求阶段,再详细debug请求链路的完整过程
web.xml回顾
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  5.          version="4.0">
  6.        
  7.         <servlet>
  8.                 <servlet-name>mvc</servlet-name>
  9.                 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  10.                 <init-param>
  11.                         <param-name>contextConfigLocation</param-name>
  12.                         <param-value>classpath:mvc-servlet.xml</param-value>
  13.                        
  14.                 </init-param>
  15.                
  16.                 <load-on-startup>1</load-on-startup>
  17.         </servlet>
  18.         <servlet-mapping>
  19.                 <servlet-name>mvc</servlet-name>
  20.                 <url-pattern>/</url-pattern>
  21.         </servlet-mapping>
  22. </web-app>                                                                                                                
复制代码
从上面的配置,我们可以看出,web.xml中的DS是一个servlet,那就从java web的servlet规范说起
上面类关系,我们说过,springmvc的范畴里,最顶层的是 HttpServletBean 继承的 标准 HttpServlet
1、ioC Bean初始化
org.springframework.web.servlet.HttpServletBean#init
2、9大组件初始化(ioC)
org.springframework.web.servlet.HttpServletBean#init
启动:servlet规范,init方法被容器调用
在servlet实例化后,被容器调用一次init方法,所以启动我们找到mvc里的父类从init看起

总结:方法调用关系(伪代码)
  1. HttpServletBean{
  2.   init(){
  3.     protected initServletBean();
  4.   }
  5. }
  6. FrameworkServlet extends HttpServletBean{
  7.   @Override
  8.   initServletBean(){
  9.     initWebApplicationContext(){
  10.       WebApplicationContext wac = createWebApplicationContext(rootContext);
  11.       protected onRefresh(wac);
  12.     }
  13.   }
  14. }
  15. DispatcherServlet extends FrameworkServlet{
  16.   onRefresh(wac){
  17.     initStrategies(wac){
  18.               //多文件上传的组件
  19.         initMultipartResolver(context);
  20.         //初始化本地语言环境
  21.         initLocaleResolver(context);
  22.         //初始化模板处理器
  23.         initThemeResolver(context);
  24.         //初始化处理器映射器
  25.         initHandlerMappings(context);
  26.         //初始化处理器适配器
  27.         initHandlerAdapters(context);
  28.         //初始化异常拦截器
  29.         initHandlerExceptionResolvers(context);
  30.         //初始化视图预处理器
  31.         initRequestToViewNameTranslator(context);
  32.         //初始化视图转换器
  33.         initViewResolvers(context);
  34.         //FlashMap 管理器
  35.         initFlashMapManager(context);
  36.     }
  37.   }
  38. }
复制代码
1.3.2 MVC请求阶段

需求:我们在浏览器输入http://localhost:8080/spring-test-mvc/index,背后到底做了哪些事情
目标:MVC如何通过一个url就能找到我们的controller,并返回数据
1、断点调试
2、流程图对照
3、继承关系对照
流程图解:
标准Servlet(回顾tomcat源码里,容器最后调的是wrapper的 service 方法)
伪代码
  1. interface Servlet{
  2.         service()  // 1  , 标准servlet规范的入口
  3. }
  4. HttpServlet implements Servlet{
  5.         public service(ServletRequest req, ServletResponse res){
  6.                 //转成 HttpServletRequest
  7.                 protected service(req,res);  // 2
  8.         }
  9.         protected service(HttpServletRequest req, HttpServletResponse resp){
  10.                 if(isGet){
  11.                         protected doGet()  // 4
  12.                 }               
  13.         }
  14.         protected void doGet(HttpServletRequest req, HttpServletResponse resp);  // 5
  15. }
  16. //spring mvc
  17. FrameworkServlet extends HttpServlet{
  18.         @Override
  19.         service(){
  20.                 super.service();  // 3
  21.         }
  22.        
  23.         protected void doGet(HttpServletRequest req, HttpServletResponse resp){
  24.                 processRequest(request, response){
  25.                         protected doService(request, response); // 6
  26.                 }   
  27.         }
  28. }
  29. DispatcherServlet extends FrameWorkServlet{
  30.         protected doService(request, response);  //  7  , here!
  31. }
复制代码
代码查找的路径:

tips:
spring mvc的  FrameworkServlet ,这是我们源码跟踪的入口
项目启动
访问
  1. http://localhost:8080/spring-test-mvc/index
复制代码
上图的初始化流程在源码中是怎么流转的呢?
入口:开启请求的大门
org.springframework.web.servlet.FrameworkServlet:
java web标准告诉我们,request的get会交给标准 HttpServlet的doGet方法
而这个类FrameworkServlet,是HttpServlet的子类,覆盖了上述的doGet,
所以,请求进入spring的第一入口,就在这里!!!
1)org.springframework.web.servlet.FrameworkServlet#doGet
调用到了org.springframework.web.servlet.FrameworkServlet#doGet
  1.         //get请求调用
  2.         @Override
  3.         protected final void doGet(HttpServletRequest request, HttpServletResponse response)
  4.                         throws ServletException, IOException {
  5.                 processRequest(request, response);
  6.         }
复制代码
2)org.springframework.web.servlet.FrameworkServlet#processRequest
  1. //        重点关注:doService
  2.         protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
  3.                         throws ServletException, IOException {
  4.                 long startTime = System.currentTimeMillis();
  5.                 Throwable failureCause = null;
  6.                 LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
  7.                 LocaleContext localeContext = buildLocaleContext(request);
  8.                 RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
  9.                 ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
  10.                 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  11.                 asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
  12.                 initContextHolders(request, localeContext, requestAttributes);
  13.                 try {
  14.                         //重点查看,跳到DispatcherServlet 类中(子类重写)
  15.                         doService(request, response);
  16.                 } catch (ServletException | IOException ex) {
  17.                         failureCause = ex;
  18.                         throw ex;
  19.                 } catch (Throwable ex) {
  20.                         failureCause = ex;
  21.                         throw new NestedServletException("Request processing failed", ex);
  22.                 } finally {
  23.                         resetContextHolders(request, previousLocaleContext, previousAttributes);
  24.                         if (requestAttributes != null) {
  25.                                 requestAttributes.requestCompleted();
  26.                         }
  27.                         if (logger.isDebugEnabled()) {
  28.                                 if (failureCause != null) {
  29.                                         this.logger.debug("Could not complete request", failureCause);
  30.                                 } else {
  31.                                         if (asyncManager.isConcurrentHandlingStarted()) {
  32.                                                 logger.debug("Leaving response open for concurrent processing");
  33.                                         } else {
  34.                                                 this.logger.debug("Successfully completed request");
  35.                                         }
  36.                                 }
  37.                         }
  38.                         publishRequestHandledEvent(request, response, startTime, failureCause);
  39.                 }
  40.         }
复制代码
3)org.springframework.web.servlet.DispatcherServlet#doService
  1.         //重写父类
  2.         //重点关注  doDispatch(request, response);
  3.         @Override
  4.         protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  5.                 if (logger.isDebugEnabled()) {
  6.                         String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
  7.                         logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
  8.                                         " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
  9.                 }
  10.                 // Keep a snapshot of the request attributes in case of an include,
  11.                 // to be able to restore the original attributes after the include.
  12.                 Map<String, Object> attributesSnapshot = null;
  13.                 if (WebUtils.isIncludeRequest(request)) {
  14.                         attributesSnapshot = new HashMap<>();
  15.                         Enumeration<?> attrNames = request.getAttributeNames();
  16.                         while (attrNames.hasMoreElements()) {
  17.                                 String attrName = (String) attrNames.nextElement();
  18.                                 if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
  19.                                         attributesSnapshot.put(attrName, request.getAttribute(attrName));
  20.                                 }
  21.                         }
  22.                 }
  23.                 // Make framework objects available to handlers and view objects.
  24.                 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
  25.                 request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
  26.                 request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
  27.                 request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
  28.                 if (this.flashMapManager != null) {
  29.                         FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
  30.                         if (inputFlashMap != null) {
  31.                                 request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
  32.                         }
  33.                         request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
  34.                         request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
  35.                 }
  36.                 try {
  37.                         //重点关注
  38.                         doDispatch(request, response);
  39.                 }
  40.                 finally {
  41.                         if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  42.                                 // Restore the original attribute snapshot, in case of an include.
  43.                                 if (attributesSnapshot != null) {
  44.                                         restoreAttributesAfterInclude(request, attributesSnapshot);
  45.                                 }
  46.                         }
  47.                 }
  48.         }
复制代码
进入核心
4)org.springframework.web.servlet.DispatcherServlet#doDispatch
  1. //        Spring MVC的最核心代码
  2.         protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  3.                 HttpServletRequest processedRequest = request;
  4.                 HandlerExecutionChain mappedHandler = null;
  5.                 boolean multipartRequestParsed = false;
  6.                 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  7.                 try {
  8.                         //创建视图对象
  9.                         ModelAndView mv = null;
  10.                         Exception dispatchException = null;
  11.                         try {
  12.                                 //请求检查,是否文件上传请求(二进制请求)
  13.                                 processedRequest = checkMultipart(request);
  14.                                 multipartRequestParsed = (processedRequest != request);
  15. //                                根据当前的请求去拿一个Handler.这个Handler其实就是我们的控制器,进入!!!!!
  16.                                 mappedHandler = getHandler(processedRequest);
  17.                                 if (mappedHandler == null) {
  18.                                         noHandlerFound(processedRequest, response);
  19.                                         return;
  20.                                 }
  21.                                 // 处理器适配器,9大组件初始化
  22.                                 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  23.                                 // Process last-modified header, if supported by the handler.
  24.                                 String method = request.getMethod();
  25.                                 //get方法为true
  26.                                 boolean isGet = "GET".equals(method);
  27.                                 //method为get
  28.                                 if (isGet || "HEAD".equals(method)) {
  29.                                         long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  30.                                         if (logger.isDebugEnabled()) {
  31.                                                 logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
  32.                                         }
  33.                                         if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
  34.                                                 return;
  35.                                         }
  36.                                 }
  37.                                 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  38.                                         return;
  39.                                 }
  40.                                 // 执行我们的业务控制器方法,com.spring.mvc.test.MvcController.getModeAndView
  41.                                 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  42.                                 if (asyncManager.isConcurrentHandlingStarted()) {
  43.                                         return;
  44.                                 }
  45.            //视图解析器
  46.                                 applyDefaultViewName(processedRequest, mv);
  47.                                 mappedHandler.applyPostHandle(processedRequest, response, mv);
  48.                         }
  49.                         catch (Exception ex) {
  50.                                 dispatchException = ex;
  51.                         }
  52.                         catch (Throwable err) {
  53.                                 // As of 4.3, we're processing Errors thrown from handler methods as well,
  54.                                 // making them available for @ExceptionHandler methods and other scenarios.
  55.                                 dispatchException = new NestedServletException("Handler dispatch failed", err);
  56.                         }
  57.                         //视图渲染
  58.                         processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  59.                 }
  60.                 catch (Exception ex) {
  61.                         triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  62.                 }
  63.                 catch (Throwable err) {
  64.                         triggerAfterCompletion(processedRequest, response, mappedHandler,
  65.                                         new NestedServletException("Handler processing failed", err));
  66.                 }
  67.                 finally {
  68.                         if (asyncManager.isConcurrentHandlingStarted()) {
  69.                                 // Instead of postHandle and afterCompletion
  70.                                 if (mappedHandler != null) {
  71.                                         mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
  72.                                 }
  73.                         }
  74.                         else {
  75.                                 // Clean up any resources used by a multipart request.
  76.                                 if (multipartRequestParsed) {
  77.                                         cleanupMultipart(processedRequest);
  78.                                 }
  79.                         }
  80.                 }
  81.         }
复制代码
5)org.springframework.web.servlet.DispatcherServlet#getHandler
  1.         @Nullable
  2.         protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  3.                 //不止一个,比如BeanNameHandlerMapping、SimpleUrlHandlerMapping,还有我们需要的RequestHandlerMapping
  4.                 //在9个组件初始化的时候赋值
  5.                 if (this.handlerMappings != null) {
  6.                         for (HandlerMapping hm : this.handlerMappings) {
  7.                                 if (logger.isTraceEnabled()) {
  8.                                         logger.trace(
  9.                                                         "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
  10.                                 }
  11.                                 //这个就是执行器链
  12.                                 HandlerExecutionChain handler = hm.getHandler(request);
  13.                                 if (handler != null) {
  14.                                         return handler;
  15.                                 }
  16.                         }
  17.                 }
  18.                 return null;
  19.         }
复制代码
org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter
  1.         protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  2.                 if (this.handlerAdapters != null) {
  3.                         for (HandlerAdapter ha : this.handlerAdapters) {
  4.                                 if (logger.isTraceEnabled()) {
  5.                                         logger.trace("Testing handler adapter [" + ha + "]");
  6.                                 }
  7.                                 if (ha.supports(handler)) {
  8.                                         return ha;
  9.                                 }
  10.                         }
  11.                 }
  12.                 throw new ServletException("No adapter for handler [" + handler +
  13.                                 "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  14.         }
复制代码
6) 调用业务Controller
  1. // 执行我们的业务控制器方法,com.spring.mvc.test.MvcController.getModeAndView
  2. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
复制代码
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInterna
  1.         @Override
  2.         protected boolean supportsInternal(HandlerMethod handlerMethod) {
  3.                 return true;
  4.         }
  5.         @Override
  6.         protected ModelAndView handleInternal(HttpServletRequest request,
  7.                         HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
  8.                 ModelAndView mav;
  9.                 checkRequest(request);
  10.                 // Execute invokeHandlerMethod in synchronized block if required.
  11.                 if (this.synchronizeOnSession) {
  12.                         HttpSession session = request.getSession(false);
  13.                         if (session != null) {
  14.                                 Object mutex = WebUtils.getSessionMutex(session);
  15.                                 synchronized (mutex) {
  16.                                         mav = invokeHandlerMethod(request, response, handlerMethod);
  17.                                 }
  18.                         }
  19.                         else {
  20.                                 // No HttpSession available -> no mutex necessary
  21.                                 mav = invokeHandlerMethod(request, response, handlerMethod);
  22.                         }
  23.                 }
  24.                 else {
  25.                         // No synchronization on session demanded at all...
  26.                         mav = invokeHandlerMethod(request, response, handlerMethod);
  27.                 }
  28.                 if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
  29.                         if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
  30.                                 applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
  31.                         }
  32.                         else {
  33.                                 prepareResponse(response);
  34.                         }
  35.                 }
  36.                 return mav;
  37.         }
复制代码
7)org.springframework.web.servlet.DispatcherServlet#processDispatchResult
  1. //1、请求视图解析器,解析成view
  2.         //2、执行页面渲染
  3.         private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
  4.                         @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
  5.                         @Nullable Exception exception) throws Exception {
  6.                 boolean errorView = false;
  7.        //如果异常不为空
  8.                 if (exception != null) {
  9.                         if (exception instanceof ModelAndViewDefiningException) {
  10.                                 logger.debug("ModelAndViewDefiningException encountered", exception);
  11.                                 mv = ((ModelAndViewDefiningException) exception).getModelAndView();
  12.                         }
  13.                         else {
  14.                                 Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
  15.                                 mv = processHandlerException(request, response, handler, exception);
  16.                                 errorView = (mv != null);
  17.                         }
  18.                 }
  19.                 //视图渲染,响应视图
  20.                 if (mv != null && !mv.wasCleared()) {
  21.                         //执行渲染
  22.                         render(mv, request, response);
  23.                         if (errorView) {
  24.                                 WebUtils.clearErrorRequestAttributes(request);
  25.                         }
  26.                 }
  27.                 else {
  28.                         if (logger.isDebugEnabled()) {
  29.                                 logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
  30.                                                 "': assuming HandlerAdapter completed request handling");
  31.                         }
  32.                 }
  33.                 if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  34.                         // Concurrent handling started during a forward
  35.                         return;
  36.                 }
  37.                 if (mappedHandler != null) {
  38.                         mappedHandler.triggerAfterCompletion(request, response, null);
  39.                 }
  40.         }
复制代码
本文由传智教育博学谷教研团队发布。
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。
转载请注明出处!
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表