SpringMVC执行流程、Servlet执行流程 、SpringMVC源码解析

Spring MVC源码解析

1 Spring MVC基于XML配置开发

需要开发者手动去定义配置文件,处理器的配置、实现特定接口、视图的配置、包扫描等的配置…都是基于XML文件来完成。

Spring MVC核心组件。SpringMVC执行流程:

1.客户端浏览器发送请求给服务器中的前端控制器DispatcherServlet;
2.⽤户根据请求中的url路径,通过HandlerMapping处理器映射器,找到匹配的Controller;
3.HandlerMapping返回⼀个处理器执⾏链,包括N个拦截器与1个Controller的处理器。并把处理器执⾏链,返回
给前端控制器DispatcherServlet;
4.前端控制器DispatcherServlet得到处理器执⾏链之后,把Controller的Handler发送给HandlerAdapter处
理器适配器;
5.HandlerAdapter根据supports(Object handler)⽅法,也就是内部的匹配规则,判断该处理器Handler是否
实现了Controller接⼝;
6.Handler处理器找到具体的⽅法handler.handleRequest(request, response),根据请求执⾏Controller
类中的⽅法;
7.Controller类执⾏完毕,然后返回⼀个ModelAndView对象给Handler处理器;
8.Handler处理器把ModelAndView对象返回给HandlerAdapter;
9.HandlerAdapter把ModelAndView对象返回给前端控制器DispathcerServlet;
10.DispathcerServlet把ModelAndView对象传递给ViewResolver视图解析器,根据jsp⻚⾯的名称拼接路;
11.ViewResolver视图解析器返回给DispathcerServlet前端控制器;
12.DispathcerServlet拿到jsp路径,由web容器对jsp⻚⾯进⾏视图渲染;
13.Web容器把响应结果返回给浏览器

在这里插入图片描述

2 Spring MVC基于XML配置的实现

1.创建一个项目:springmvc_code。创建成Java企业级的项目。

  • JSP本质上就是Servlet(组件)。
  • 如果使用原生的Servlet响应网页给客户端,需要使用PrintWriter的write(“xxx”)或者是println(“xxx”)。
  • 将HTML代码抽离出来,定义在其他的文件中,使用动态拼接渲染,最终响应给客户端。
  • 在JSP文件中可以直接定义网页的代码结构。可以通过EL表达式、JSTL标签库来完成页面的动态数据加载。
  • Tomcat在编译JSP文件(Hello.jsp)的时候,将JSP转化成一个Servlet组件(Hello_jsp.java - Java源文件)。最后经过JVM虚拟机将Servlet组件转化成一个字节码文件(Hello_jsp.class)。

2.创建了一个Hello.jsp文件。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>SpringMVC基于XML文件的配置开发</title>
</head>
<body>
    <h1>SpringMVC基于XML文件的配置开发</h1>
    <p>数据展示:${msg}</p>
</body>
</html>

3.编写Web.xml核心配置文件:配置DispacherServlet、配置编码设置、springmvc-servlet.xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="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_4_0.xsd"
         version="4.0">
  <!-- 1.注册Servlet -->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <!-- 2.配置映射 -->
  <servlet-mapping>
    <!-- 上下定义的名称需要保持一致 -->
    <servlet-name>springmvc</servlet-name>
    <!-- 表示请求的url映射: "/"表示能够匹配浏览器提交过来的所有请求 -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

4.Servlet的原理是什么?
在这里插入图片描述
或者:
image-20221124184334453

5.创建一个HelloController类。

package com.qf.springmvc_code.controller;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 自定义控制器类: SpringMVC框架提供的一个接口Controller
 */
public class HelloController implements Controller { // URL访问地址基于XML配置的方式进行开发
    /**
     * 该方法什么时候被调用?
     * 1.请求的url找了到了对象的Controller类之后,此Controller类中的handleRequest()方法会被自动回调。
     * 2.ModelAndView: 模型和视图。
     *   - 模型:表示数据,可以在ModelAndView对象上绑定数据。
     *   - 视图:表示一个数据展示的页面,例如是一个JSP页面。
     */
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        /**
         * 需求:配置的请求地址是"/hello",一旦访问该请求,服务器打开Hello.jsp文件,然后该jsp文件输出"Hello SpringMVC"信息。
         */
        // 1.创建一个模型和视图对象
        ModelAndView modelAndView = new ModelAndView();
        // 2.在modelAndView对象上绑定数据(key-value键值对)
        modelAndView.addObject("msg", "Hello Spring MVC");
        /**
         * 3.设置视图:表示将来跳转到那一个指定的视图页面(Hello.jsp页面)
         *   - 前缀:/WEB-INF/
         *   - 后缀:.jsp
         */
        modelAndView.setViewName("hello"); // 表示访问的是/WEB-INF/hello.jsp页面
        // 4.将模型和视图对象返回给调用者
        return modelAndView;
    }
}

6.Controller接口分析:

@FunctionalInterface // 函数式接口
public interface Controller {
	// 用来处理请求和响应(request和response对象会自动的传递给此方法)
  @Nullable
  ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

7.默认情况下,SpringMVC框架自动去/WEB-IN/springmvc-servlet.xml此配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 1.注册处理器映射器:HandlerMapping
         作用:处理器映射器会根据请求的url地址,将url和Spring容器中的一个bean的name属性值进行匹配。
         说明:bean标签没有显示的什么id属性的取值,Spring容器会自动的为其分配一个id的值(自定生成),
              id生成规则是:包名.类名#数字。例如:id=com.qf.springmvc_code.controller.HelloController#1 -->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

    <!-- 2.注册处理器(HelloController类)
         name属性:表示对应一个前端的请求,name属性的取值必须使用"/"开头
         class属性:表示对应请求从DispatcherServlet发送过来的请求,对应的的后台处理器 -->
    <bean name="/hello" class="com.qf.springmvc_code.controller.HelloController"></bean>

    <!-- 3.配置处理器适配器:HandlerAdapter
         作用:根据HandlerMapping返回的Controller,执行一个匹配的规则,主要是找到对应的Handler去处理Controller。 -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>

    <!-- 4.配置视图解析器:ViewResolver
         作用:根据路径的前缀和后缀找到对应的视图文件,然后进行渲染 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 4.1 配置资源文件的路径前缀 -->
        <property name="prefix" value="/WEB-INF/"></property> <!-- 表示给一个属性配置初始化取值的数据 -->
        <!-- 4.2 配置资源文件的后缀(文件扩展名称) -->
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

8.启动服务器,访问项目。

image-20221124184507679

image-20221124184542753

3 SpringMVC源码解析

3.1 前端控制器DispatcherServlet

1.继承关系:

DispatcherServlet继承 - FrameworkServlet继承 - HttpServletBean继承 - HttpServlet继承 - GenericServlet结成 - Servlet接口。

image-20221124184554387

2.DispatcherServlet前端控制器:等待请求和响应,一个方法doDispatch()。

// Servlet接口中提供的一个方法,根据不同的请求类型来进行请求的处理
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  // ...
  
  // 调用了doDispatch()方法,传递了请求和响应对象
  this.doDispatch(request, response);
}

3.doDispatch方法定义。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  HttpServletRequest processedRequest = request;
  // 创建一个处理器执行链(将来执行请求的流程)
  HandlerExecutionChain mappedHandler = null;
  boolean multipartRequestParsed = false;
  WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

  try {
    try {
      ModelAndView mv = null;
      Object dispatchException = null;

      try {
        processedRequest = this.checkMultipart(request);
        multipartRequestParsed = processedRequest != request;
        // 通过getHandler(request)返回一个处理器执行链对象
        mappedHandler = this.getHandler(processedRequest);
        
        if (mappedHandler == null) {
          this.noHandlerFound(processedRequest, response);
          return;
        }

        HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
        String method = request.getMethod();
        boolean isGet = HttpMethod.GET.matches(method);
        if (isGet || HttpMethod.HEAD.matches(method)) {
          long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
          if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
            return;
          }
        }

        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
          return;
        }

        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        if (asyncManager.isConcurrentHandlingStarted()) {
          return;
        }

        this.applyDefaultViewName(processedRequest, mv);
        mappedHandler.applyPostHandle(processedRequest, response, mv);
      } catch (Exception var20) {
        dispatchException = var20;
      } catch (Throwable var21) {
        dispatchException = new NestedServletException("Handler dispatch failed", var21);
      }

      this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
    } catch (Exception var22) {
      this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
    } catch (Throwable var23) {
      this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
    }

  } finally {
    if (asyncManager.isConcurrentHandlingStarted()) {
      if (mappedHandler != null) {
        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
      }
    } else if (multipartRequestParsed) {
      this.cleanupMultipart(processedRequest);
    }

  }
}

4.查看getHandler(processedRequest)的源码。

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  if (this.handlerMappings != null) { // 维护的是url和Controller的映射
    Iterator var2 = this.handlerMappings.iterator();

    // HandlerMapping是Servlet所支持的处理器映射器的一个集合,这里可能会有N个处理器映射器
    while(var2.hasNext()) {
      // 举例:/hello - HelloController对象
      HandlerMapping mapping = (HandlerMapping)var2.next(); // url映射Controller
      // 返回一个处理器执行链
      HandlerExecutionChain handler = mapping.getHandler(request);
      if (handler != null) {
        return handler;
      }
    }
  }

  return null;
}

5.查看getHandler(request)方法的源码。HandlerMapping接口有一个实现类:AbstractHandlerMapping类。

@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  // 获取一个Handler对象
  Object handler = this.getHandlerInternal(request);
  if (handler == null) {
    handler = this.getDefaultHandler();
  }

  if (handler == null) {
    return null;
  } else {
    if (handler instanceof String) {
      String handlerName = (String)handler;
      handler = this.obtainApplicationContext().getBean(handlerName);
    }

    if (!ServletRequestPathUtils.hasCachedPath(request)) {
      this.initLookupPath(request);
    }

    // 获取处理器执行链。根据request请求对象和一个处理器Handler对象来获取处理器执行链
    HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
    if (this.logger.isTraceEnabled()) {
      this.logger.trace("Mapped to " + handler);
    } else if (this.logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
      this.logger.debug("Mapped to " + executionChain.getHandler());
    }

    if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
      CorsConfiguration config = this.getCorsConfiguration(handler, request);
      if (this.getCorsConfigurationSource() != null) {
        CorsConfiguration globalConfig = this.getCorsConfigurationSource().getCorsConfiguration(request);
        config = globalConfig != null ? globalConfig.combine(config) : config;
      }

      if (config != null) {
        config.validateAllowCredentials();
      }

      executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
  }
}

6.查看getHandlerInternal(request)方法。

// 获取一个Controller
@Nullable
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

7.查看getHandlerExecutionChain(handler, requst)方法。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  // 获取一个处理器执行链对象
  HandlerExecutionChain chain = 
    handler instanceof HandlerExecutionChain ? 
   (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
  
  Iterator var4 = this.adaptedInterceptors.iterator();

  while(var4.hasNext()) {
    HandlerInterceptor interceptor = (HandlerInterceptor)var4.next();
    if (interceptor instanceof MappedInterceptor) {
      MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
      // request:对象中就有目标的url地址,例如是/hello
      // HandlerMapping获取的映射,url得知
      if (mappedInterceptor.matches(request)) {
        // 这里可以看出具有多个拦截器,而且拦截器根据请求做匹配
        chain.addInterceptor(mappedInterceptor.getInterceptor());
      }
    } else {
      chain.addInterceptor(interceptor);
    }
  }
	// 处理器执行链:包含两部分内容。interceptor和handler。
  return chain;
}

DispathcherServlet前端控制器,经过一系列的处理返回一个处理器执行链对象(HandlerExecutionChain)。在该对象封装了两部信息,分别是Interceptor拦截器和一个Handler处理器。

8.配置初始化参数信息。

<servlet>
  <servlet-name>springmvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!-- 给当前的Servlet配置初始化参数:配置的是springmvc框架的核心配置文件的位置 -->
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
  </init-param>
</servlet>

9.XmlWebApplicationContext类维护了SpringMVC的核心配置文件的加载。

/**
 * The default location for the root context is "/WEB-INF/applicationContext.xml",
 * and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"
 * (like for a DispatcherServlet instance with the servlet-name "test").
 * 项目的根目录的上下文位置"/WEB-INF/applicationContext.xml"找核心配置文件。或者通过"/WEB-INF/test-servlet.xml"路径来找配置文件,规则是:通过DispacherServlet的name属性的取值,来进行获取文件的,在name属性的取值后自动添加"-servlet"作为被寻找的配置文件名称。
 */
@Override
protected String[] getDefaultConfigLocations() {
  if (getNamespace() != null) {
    return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
  }
  else {
    return new String[] {DEFAULT_CONFIG_LOCATION};
  }
}
3.2 处理器映射器HandlerMapping

HandlerMapping接口负责将request对象和请求找到的Handler对象及interceptor对象,封装到处理器执行链(HandlerExcecationChain)中,返回给前端控制器(DispacherSerlvet)。

HandlerMapping接口提供了两个实现类:

  • BeanNameUrlHandlerMapping
  • SimpleUrlHandlerMapping

1.BeanNameUrlHandlerMapping

BeanNameUrlHandlerMapping处理器映射器会根据请求的url与Spring中定义Controller的name属性的取值进行匹配(Spring容器中定义的Bean类的name属性进行匹配)。如果匹配成功,则返回一个处理器对象(Controller对象)。

1.xml文件中的配置。

<!-- 1.注册处理器映射器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- 2.注册处理器(Controller) -->
<bean name="/hello" class="com.qf.springmvc_code.controller.HelloController"></bean>

2.BeanNameUrlHandlerMapping类的源码解析。

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
  // 构造方法
  public BeanNameUrlHandlerMapping() {
  }

  // 检查给定的bean的name属性的取值是否以“/”开头,如果是,则添加到String[]数组中了
  protected String[] determineUrlsForHandler(String beanName) { // name="/hello"
    List<String> urls = new ArrayList(); // List集合是用来存储url的(name属性的值的集合)
    if (beanName.startsWith("/")) { // 判断name属性的取值是否以"/"开头
      urls.add(beanName); // 将这个name的取值添加到List集合中
    }

    String[] aliases = this.obtainApplicationContext().getAliases(beanName);
    String[] var4 = aliases;
    int var5 = aliases.length;

    for(int var6 = 0; var6 < var5; ++var6) {
      String alias = var4[var6];
      if (alias.startsWith("/")) {
        urls.add(alias); // 如果bean别名以“/”开头,则将别名添加到List集合中
      }
    }

    // List<String> 转化成 String[]
    return StringUtils.toStringArray(urls);
  }
}

3.需求:

  • 访问 /hello,可以打开HelloController。
  • 访问/world,可以打开HelloController。
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>

<bean name="/hello" class="com.qf.springmvc_code.controller.HelloController"></bean>
<bean name="/world" class="com.qf.springmvc_code.controller.HelloController"></bean>

4.BeanNameUrlHandlerMapping缺点:

  • 注册处理器的时候,如果有多个url映射同一个Controller,代码极为冗余。
  • Controller处理器url要求不能重复,而bean标签name属性的值是可以重复。如果就显得不伦不类。

2.SimpleUrlHandlerMapping

SimpleUrlHandlerMapping实现方式分为两种。

<!--1.注册处理器映射器:SimpleUrlHandlerMapping -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <!-- 方式2:urlMap的属性来实现请求地址的映射-->
  <property name="urlMap">
    <map>
      <!-- entry表示表示一组url与Controller的映射。key表示请求的url地址,value表示Controller的bean标签对应的id属性的值 -->
      <entry key="/hello" value="helloController" />
      <entry key="/world" value="helloController" />
    </map>
  </property>

  <!-- 方式1:通过mappings属性完成的-->
  <!--
mappings属性:通过mappings属性来为当前的处理器同时配置多个url地址的请求映射
<property name="mappings">
<props>
prop表示声明一组url的映射,其中key表示配置请求地址,prop标签的内容是Controller的bean的id取值
<prop key="/hello">helloController</prop>
<prop key="/world">helloController</prop>
</props>
</property>
-->
</bean>
<!--2.注册处理器: HelloController-->
<bean id="helloController" class="com.qf.springmvc_code.controller.HelloController"></bean>

3.HandlerMapping的源码解析

1.DispacherServlet类中doService(request, response)。

this.doDispatch(request, response);

2.doDispatch(request, response)方法。需要接受一个request请求对象。

mappedHandler = this.getHandler(processedRequest);

3.getHandler(processedRequest)方法。

// List集合中存放的是所有的HandlerMapping对象
@Nullable
private List<HandlerMapping> handlerMappings;

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  if (this.handlerMappings != null) {
    Iterator var2 = this.handlerMappings.iterator();

    // 遍历HandlerMappings的集合
    while(var2.hasNext()) {
      // 获取一个HandlerMapping类型的对象
      HandlerMapping mapping = (HandlerMapping)var2.next();
      // 通过request请求来获取HandlerMapping处理器执行链
      HandlerExecutionChain handler = mapping.getHandler(request);
      if (handler != null) {
        return handler;
      }
    }
  }

  return null;
}

4.getHandler(request)方法。是在AbstractHandlerMapping中实现了该方法。

@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  // 根据请求对象获取一个处理器
  Object handler = this.getHandlerInternal(request);
  if (handler == null) {
    handler = this.getDefaultHandler();
  }

  if (handler == null) {
    return null;
  } else {
    if (handler instanceof String) {
      String handlerName = (String)handler;
      handler = this.obtainApplicationContext().getBean(handlerName);
    }

    if (!ServletRequestPathUtils.hasCachedPath(request)) {
      this.initLookupPath(request);
    }

    // 根据request和response对象来获取一个处理器执行链(HandlerExecutionChain)
    HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
    if (this.logger.isTraceEnabled()) {
      this.logger.trace("Mapped to " + handler);
    } else if (this.logger.isDebugEnabled() && !DispatcherType.ASYNC.equals(request.getDispatcherType())) {
      this.logger.debug("Mapped to " + executionChain.getHandler());
    }

    if (this.hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
      CorsConfiguration config = this.getCorsConfiguration(handler, request);
      if (this.getCorsConfigurationSource() != null) {
        CorsConfiguration globalConfig = this.getCorsConfigurationSource().getCorsConfiguration(request);
        config = globalConfig != null ? globalConfig.combine(config) : config;
      }

      if (config != null) {
        config.validateAllowCredentials();
      }

      executionChain = this.getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
  }
}

5.getHandlerExecutionChain()方法。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  // 实例化一个HandlerExecutionChain对象
  HandlerExecutionChain chain = 
    	handler instanceof HandlerExecutionChain ? 
    	(HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
  Iterator var4 = this.adaptedInterceptors.iterator();

  while(var4.hasNext()) {
    // 创建一个处理器过滤器对象
    HandlerInterceptor interceptor = (HandlerInterceptor)var4.next();
    if (interceptor instanceof MappedInterceptor) {
      // 转化成一个MappedInterceptor过滤器
      MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
      if (mappedInterceptor.matches(request)) { // 判断请求对象中的url和配置是否相同
        // 把这个过滤器添加到HandlerExecutionChain对象中
        chain.addInterceptor(mappedInterceptor.getInterceptor());
      }
    } else {
      chain.addInterceptor(interceptor);
    }
  }
	// 返回一个HandlerExecutionChain对象:handler、interceptor(request)
  return chain;
}

HandlerMapping处理器映射器,通过源码分析返回一个HandlerExecutionChain的对象(包含了url和Controller的映射)。

3.3 处理器适配器HandlerAdapater

1.HandlerAdapater源码分析

1.找到DispacherSerlvet类中doService方法。

this.doDispatch(request, response);

2.查看doDispatch(request, response)方法。

// doDispatch(request, response)方法中中getHandlerAdapter方法返回一个HandlerAdapater对象
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());

3.getHandlerAdapter(mappedHandler.getHandler())方法。

// 方法通过Handler对象来返回一个HandlerAdapter对象
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  if (this.handlerAdapters != null) { // List<HandlerAdapter>集合中
    Iterator var2 = this.handlerAdapters.iterator();

    while(var2.hasNext()) {
      // 获取集合中的HandlerAdapter对象
      HandlerAdapter adapter = (HandlerAdapter)var2.next();
      if (adapter.supports(handler)) { // 调用HandlerAdapter的supports方法
        return adapter;
      }
    }
  }

  throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

4.supports(handler)方法。方式是有SimpleControllerHandlerAdapter类实现的。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
  // 构造方法
  public SimpleControllerHandlerAdapter() {
  }

  // 传递的Handler对象是HelloController
  // HelloController类的定义public class HelloController implements Controller
  public boolean supports(Object handler) {
    // 通过传递过来的Handler对象,判断该对象是否是Controller类型
    return handler instanceof Controller;
  }

  /**
   * 参数1:表示一个request请求对象
   * 参数2:表示一个response请求对象
   * 参数3:表示一个Controller对象(HelloController)
   */
  
  @Nullable
  public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    // 多态:向上转型。调用handleRequest(request, response)方法来完成请求处理业务逻辑
    return ((Controller)handler).handleRequest(request, response);
  }

  // 与HttpSerlvet的getLastModified方法的约定时间。
  public long getLastModified(HttpServletRequest request, Object handler) {
    return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
  }
}

2.HandlerAdapter的执行

DispacherServlet会根据HandlerMapping传递回来的Controller注册到以配置的HandlerAdapter上。HandlerAdapater来判断Controller的数据类型是否满足满足要求(Controller), 如果类型满足要求,则将该Controller进行类型转化(Controller接口类型)。调用目标Controller的HandleRequest(request, response)方法,来完成目标业务逻辑方法的调用。

3.4 视图解析器ViewResolver

1.ViewResolver源码分析

1.InternalResourceViewResolver类的定义。

public class InternalResourceViewResolver extends UrlBasedViewResolver {
  // 通过JSTL标签库来解析目标JSP文件  
  private static final boolean jstlPresent = 
      ClassUtils.isPresent(
      							// 加载JSTL的标签标签库
      							"javax.servlet.jsp.jstl.core.Config",
      							// 获取当前类的类加载器
                    InternalResourceViewResolver.class.getClassLoader());
  
  // ...

}

2.UrlBasedViewResolver类。

public class UrlBasedViewResolver extends AbstractCachingViewResolver implements Ordered {
  public static final String REDIRECT_URL_PREFIX = "redirect:"; // 重定向
  public static final String FORWARD_URL_PREFIX = "forward:"; // 转发
  @Nullable
  private Class<?> viewClass;
  private String prefix = ""; // 目标视图的前缀(在那一个目录下存放的)
  private String suffix = ""; // 目标视图的后缀(.jsp、.asp)

}

2.ViewResolver流程

1.将SpringMVC框架的前端控制器中的返回结果封装成一个ModelAndView对象。

2.通过视图解析器,将返的ModelAndView对象进行解析,解析成一个物理地址的映射视图。

3.将这个物理地址的视图通过View接口来进行渲染。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值