SpringMvc源码流程详解


前言

在Spring源码的阅读中,我们看到了Spring预留了很多的拓展点,这写拓展点可以供我们自定义实现,也会支持与其它框架的整合,比如之前讲解的mybatis。今天,带大家深入的了解以下关于Spring主子容器的运用SpringMvc的源码知识,希望可以有所收获;


一、原生的Severlet

在开始SpringMvc的源码讲解之前,想要和大家一起回顾一下原生Severlet,SpringMVC就是在此基础上加以优化和封装而来的;

  • 代码回顾:
package com.ys.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class HelloServlet implements Servlet{

//只被调用一次,第一次请求Servlet时,创建Servlet的实例,调用构造器
	public HelloServlet() {
		System.out.println("构造器 HelloServelt()...");
	}

//该方法用于初始化Servlet,就是把该Servlet装载入内存
//只被调用一次,在创建好实例后立即被调用

	@Override
	public void init(ServletConfig config) throws ServletException {
		System.out.println("初始化方法 init()...");
	}

//被多次调用,每次请求都会调用service方法。实际用于响应请求的

	@Override
	public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
		System.out.println("执行方法主体 service()...");
	}

//只被调用一次,在当前Servlet所在的WEB应用被卸载前调用,用于释放当前Servlet所占用的资源

	@Override
	public void destroy() {
		System.out.println("servlet 销毁时调用方法 destroy()...");
	}

	@Override
	public ServletConfig getServletConfig() {
		return null;
	}

	@Override
	public String getServletInfo() {
		return null;
	}

}
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">

<!--在tomcat 服务器中运行时,如果不指名访问文件名,默认的根据项目名访问文件顺序如下配置 -->

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>

<!--给创建的 Servlet 配置映射关系 -->
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>com.ys.servlet.HelloServlet</servlet-class>
<!--servlet的完整名称-->
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<!-- 与上面配置的 servlet-name 名字要对应,一个servlet可以有多个 servlet-mapping -->
<url-pattern>/hello</url-pattern>
<!--访问路径-->
</servlet-mapping>
</web-app>
  • 代码中可以看到,通过Servlet实现动态web应用的基本简单基本步骤,通过与tomcat的搭配,会调用web.xml中配置的指定servlet的处理器中,调用顺序大致时:init-》service-》destroy,且一个servlet项目只会调用一次init和destroy方法;

二、SpringMvc是什么?

在这里插入图片描述

  • MVC设计思想:M数据层,可以是dao层和Service层,V视图层,可以理解为JSP页面,C控制层,可以理解为Sererlet处理层(DispatcherServlet)控制转发调用;
  • Spring MVC和servlet的区别是什么:1,思想层面,servlet只能是mvc设计架构的一部分,collector部分。2,springMvc隶属于Spring全家桶的一部分,所有的spring的优点都可以用到mvc上;3,约定大于配置,不要一个一个去配置servlet,简化开发流程;4,异常处理:Spring MVC提供了统一的异常处理机制,使异常处理更加清晰、一致。而Servlet需要手动处理异常。5,配置管理:Spring MVC的配置更加简洁、灵活,可以通过XML配置文件、注解等方式进行配置。而Servlet需要手动配置很多细节,如请求映射、初始化参数等。

三、SpringMvc组件?

  1. 前端控制器 DispatcherServlet
  2. 处理器映射器 HandlerMapping
  3. 处理器适配器 HandlerAdapter
  4. 视图解析器(ViewResolver)
  5. 视图渲染(View)

三、SpringMvc源码执行步骤?

1.容器加载

代码如下(示例):

  • servlet上下文监听器的contextInitialzed方法完成对Spring配置文件的解析工作(完成对父容器的解析);

  • 调用到HttpServlet的init方法完成对SPringMvc容器的解析工作,在容器中指定了监听器,在完成refresh监听后会执行九大内置主键的解析:
    在这里插入图片描述

  • MultipartResolver:MultipartResolver用于处理上传请求,处理方式是将普通的request包装成MultipartHttpServletRequest,可以直接调用getFile方法来获取File,如果上传多个文件,可以调用getFileMap来处理。

  • LocaleResolver:在ViewResolver解析视图的时候,使用到国际化资源或者主题的时候,例如根据请求头里的locale对象来确定用户的地域设置,自己写逻辑获取指定地区配置的商品价格,信息等数据。

  • ThemeResolver:主题设置,可以指定多套主题css图片/字体/格式,进行配置读取指定。

  • HandlerMappings:处理器映射器,将请求映射到对应的handler处理器中;初始化HandlerMappings对象时,先会在beanFactory中找,找不到会使用DispatcherServlet_test.properties(见下图)中默认定义的BeanNameUrlHandlerMapping,RequestMappingHandlerMapping,RouterFunctionMapping三个映射器;
    在初始化BeanNameUrlHandlerMapping对象时,由于该对象ApplicationContextAware,在spring完成实例化后再执行init方法之前会调用到其setApplicationContext方法,在调用该方法时完成了对以 / 开头bean对象put到其handlerMap属性集合中;
    在实例化RequestMappingHandlerMapping时,由于该类实现了InitializingBean方法,在执行完属性赋值后会调用其afterPropertiesSet,在该方法完成对注解的扫描与解析工作;

  • HandlerAdapters:处理器适配器,真正调用处理器且完成了对响应结果的处理,适配器模式的使用,用于将请求适配对应的处理器;初始化流程与HandlerMappings大致相同,默认定义HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapter,HandlerFunctionAdapter四种适配器;

  • HandlerExceptionResolver:基于HandlerExceptionResolver接口的异常处理,初始化流程与HandlerMappings大致相同,默认定义ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolver三种集中异常处理器;

  • RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称,比如“找不到页面”;

  • ViewResolvers:将ModelAndView选择合适的视图进行渲染的处理器;

  • FlashMapManager:用于存储并检索FlashMap。FlashMap主要用于在重定向中传递参数。
    在这里插入图片描述

2.请求调用(分发及处理)

  • 具体的调用过程
    在这里插入图片描述

  • 适配器具体执行过程
    非常典型的适配器模式的使用,为了后续便于维护调用不同类型handler处理器拓展工作。在现有的三种处理器中,实现coltroller接口和使用HttpRequestHandler接口的处理器(controller)比较方便调用,直接调用对应处理器的handleRequest方法即可,但是使用@Controller注解实现的RequestMappingHandlerAdapter处理器不确定需要调用哪个方法进行执行,所有处理逻辑比较复杂,下面对处理注解方式实现hanlder的适配器进行详细的流程介绍;
    1,初始化解析 @initBounder注解/@ModelAttribute注解/@SessionAttribute注解
    2,解析到方法的参数
    3, 使用argumentResolvers解析参数
    4,在参数接卸过程中会匹配到对应的initBounder进行对参数的增强
    5,调用到对应处理器的方法
    6,处理@ResponseStatus注解
    7,使用returnValueHandlers处理返回值
    8,完成对model的重新赋值
    9,自定义后置处理器调用
    10,完成view页面渲染

  • initBounder注解的作用:
    在controller控制器里的一个针对于当前控制器的初始化的自定义数据绑定规则,可以理解为调用到具体的方法前的拦截器,可以在调用具体方法之前进行数据校验及数据类型转换的工作;

  • @ModelAttribute注解:
    可以理解为一次请求中对model对象的赋值与运用,可以作用在参数中或方法上;在方法上可以对一次请求中的model进行赋值,在后续调用过程中可以直接获取到model并使用,作用在参数中可以将model中指定属性赋值到被修饰的参数上,方便后续使用;

  • @SessionAttribute注解:
    与ModelAttribute有相适之处,只是SessionAttribute作用在session不仅限于一次请求,且SessionAttribute只能运用在类的层面,作用就是将model指定的值放在Session存储,范围比ModelAttribute大;

  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值