写在前面:

我是「沸羊羊_」,昵称来自于姓名的缩写 fyy ,之前呕心沥血经营的博客因手残意外注销,现经营此账号。
本人是个小菜,正向着全栈工程师的方向努力着,文章可能并不高产,也很基础,但每写一篇都在用心总结,请大佬勿喷。
如果您对编程有兴趣,请关注我的动态,一起学习研究。
感谢每位读者!

文章目录

  • 认识SpringMVC
  • SpringMVC 处理请求过程
  • Servlet 与 SpringMVC
  • Structs2 与 Spring MVC
  • SpringMVC源码分析

认识SpringMVC

SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是 DispatcherServlet,它是一个 Servlet,顶层是实现的Servlet接口。


SpringMVC 处理请求过程

  • 客户端发起请求,会首先经过前端控制器 DispatcherServlet 进行转发,转发到 Handler Mapping
  • DispatcherServlet 从 Handler Mapping 查找处理请求的 Controller,Handler Mapping 作用就是完成 URL 到 Controller 的映射
  • Controller 处理请求并返回 ModelAndView 对象,ModelAndView 是封装结果视图的组件
  • 再将视图结果返回给客户端

Servlet 与 SpringMVC

SpringMVC 是在 Servlet 的基础上进行了扩展,看看他们的继承关系是什么样的。

Servlet 继承关系


SpringMVC 继承关系


Servlet 与 SpringMVC 对比

  • Servlet 需要每个请求都在 web.xml 文件中配置一个 sevlet 节点
  • SpringMVC 的 DispatcherServlet 会拦截所有请求,让 Controller 去处理

Structs2 与 Spring MVC

相同点

  • 都是基于MVC模型的

不同点

  • Structs2 是基于类的,一个 request 创建一个 action,一个action 对应一个 request ;Servlet 是基于方法的,也就是一个 request 对应一个方法
  • Structs2 入口是 Filter;SpringMVC 入口是 Servlet
  • SpringMVC 的开发速度和性能优于 Structs2 ,流程更易理解
  • SpringMVC 和 Spring 是无缝的,可以认为 SpringMVC 是100% 零配置

SpringMVC源码分析

1、ApplicationContext 初始化时建立所有的URL和Controller 的对应关系

/**
* 建立当前ApplicationContext中的所有controller和url的对应关系
*/
protected void detectHandlers() throws BeansException {//日志级别是否是 Debugif (logger.isDebugEnabled()) {//应用上下文就是工程的访问路径logger.debug("Looking for URL mappings in application context: " + getApplicationContext());}// 获取ApplicationContext容器中所有bean的Name---ControllerString[] beanNames = (this.detectHandlersInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :getApplicationContext().getBeanNamesForType(Object.class));// 遍历beanNames,并找到这些bean对应的urlfor (String beanName : beanNames) {// 获取Controller上的所有url(类上的url+方法上的url)String[] urls = determineUrlsForHandler(beanName);if (!ObjectUtils.isEmpty(urls)) {// 保存urls和beanName的对应关系,put it to Map<urls,beanName>,该方法在父类AbstractUrlHandlerMapping中实现registerHandler(urls, beanName);}else {if (logger.isDebugEnabled()) {logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");}}}
}

2、根据访问URL找到对应 Controller 中处理请求的方法

/** 中央控制器,控制请求的转发 **/
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 {// 1.检查是否是文件上传的请求processedRequest = checkMultipart(request);// 2.取得处理当前请求的controller,这里也称为hanlder,处理器,第一个步骤的意义就在这里体现了.这里并不是直接返回controller,而是返回的HandlerExecutionChain请求处理器链对象,该对象封装了handler和interceptors.mappedHandler = getHandler(processedRequest, false);// 如果handler为空,则返回404if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;}//3. 获取处理request的处理器适配器handler adapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// 处理 last-modified 请求头String method = request.getMethod();boolean isGet = "GET".equals(method);if (isGet || "HEAD".equals(method)) {long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if (logger.isDebugEnabled()) {String requestUri = urlPathHelper.getRequestUri(request);logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}// 4.拦截器的预处理方法HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();if (interceptors != null) {for (int i = 0; i < interceptors.length; i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);return;}interceptorIndex = i;}}// 5.实际的处理器处理请求,返回结果视图对象mv = ha.handle(processedRequest, response, mappedHandler.getHandler());// 结果视图对象的处理if (mv != null && !mv.hasView()) {mv.setViewName(getDefaultViewName(request));}// 6.拦截器的后处理方法if (interceptors != null) {for (int i = interceptors.length - 1; i >= 0; i--) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);}}}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);}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");}}// 请求成功响应之后的方法triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
}

3、反射调用处理请求的方法返回结果视图

/** 获取处理请求的方法,执行并返回结果视图 **/
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {// 1.获取方法解析器ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);     // 2.解析request中的url,获取处理request的方法 //通过 request 找 controller 中的处理方法,request的url与 controller 的url 进行匹配Method handlerMethod = methodResolver.resolveHandlerMethod(request);     // 3.方法调用器ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);ServletWebRequest webRequest = new ServletWebRequest(request, response);ExtendedModelMap implicitModel = new BindingAwareModelMap();// 4.执行方法Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);     // 5.封装结果视图ModelAndView mav =methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);return mav;
}

SpringMVC从基础到源码相关推荐

  1. spring源码分析第四天------springmvc核心原理及源码分析

    spring源码分析第四天------springmvc核心原理及源码分析 1.基础知识普及 2. SpringMVC请求流程 3.SpringMVC代码流程 4.springMVC源码分析 4.1 ...

  2. SpringMVC+Maven开发项目源码详细介绍

    代码地址如下: http://www.demodashi.com/demo/11638.html Spring MVC概述 Spring MVC框架是一个开源的Java平台,为开发强大的基于Java的 ...

  3. java B2B2C springmvc mybatis电子商务平台源码-Consul服务发现原理...

    Consul 是什么 Consul 是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件,由 HashiCorp 公司用 Go 语言开发, 基于 Mozilla Public License ...

  4. php 框架获取服务器,Thinkphp 框架基础之源码获取、环境要求与目录结构分析

    本文实例讲述了Thinkphp 框架基础之源码获取.环境要求与目录结构.分享给大家供大家参考,具体如下: 获取ThinkPHP 获取ThinkPHP的方式很多,官方网站(http://thinkphp ...

  5. windows C++ Opengl基础框架源码

    windows C++ Opengl基础框架源码 项目开发环境 项目功能 项目演示 项目源码传送门 项目开发环境 开发语言:C++和IDE:VS2017,操作系统Windows版本windows SD ...

  6. SpringMVC子父容器源码剖析

    SpringMVC子父容器源码剖析 一.子父容器启动流程 二.环境准备 spring源码搭建 spring-framework-5.1.x 源码编译 环境搭建 [ idea:2020.1 ] 在spr ...

  7. java B2B2C springmvc mybatis电子商务平台源码

    用java实施的电子商务平台太少了,使用spring cloud技术构建的b2b2c电子商务平台更少,大型企业分布式互联网电子商务平台,推出PC+微信+APP+云服务的云商平台系统,其中包括B2B.B ...

  8. 堪称神级的阿里巴巴“高并发”教程《基础+实战+源码+面试+架构》

    前言 作为一个普普通通的程序员,如何才能提升自己的能力,在职场上拥有一技之长,这也成为普通的你我,迫切的需求. 拥有什么样的能力才能不被淘汰?答案是:高并发,它几乎成为了每个程序员都想要拥有的经验. ...

  9. java B2B2C springmvc mybatis电子商务平台源码-服务的注册与发现(Eureka)

    1.介绍 对于微服务的治理而言,其核心就是服务的注册和发现.在SpringCloud 中提供了多种服务注册与发现组件:Eureka,Consul,Zookeeper.官方推荐使用Eureka. 需要J ...

最新文章

  1. python绘制3d图-Python绘制3D图形
  2. 开源使得所有的软件卖成白菜价,但终将普惠世界!
  3. 目前有量子计算机,中国“祖冲之”刚刚成为当前最强大的量子计算机
  4. kafka 学习 非常详细的经典教程
  5. LeetCode 1880. 检查某单词是否等于两单词之和
  6. Alibaba Sentinel规则持久化-推模式-手把手教程【基于Nacos】
  7. java代码修改触发编译_gcc -O0仍然优化了“未使用”的代码 . 是否有一个编译标志来改变它?...
  8. 51单片机如何用c语言位定义,嵌入式编程(一):51单片机如何将函数 定义到指定程序地址...
  9. 【CSS布局】已知布局元素的高度,写出三栏布局,要求左栏、右栏宽度各为300px,中间自适应。
  10. 浅谈堆(2016-12-31 09:59)错误更改
  11. paip.提升安全性-------用户口令密码的检测与生成
  12. C语言的奇技淫巧(1-50)
  13. [ 高斯消元 二分图最大匹配 ] [ HEOI2013 ] BZOJ3168 钙铁锌硒维生素
  14. C语言_关于文件内容删除的两个方法总结
  15. 第十三课、类族的结构进化-------------------狄泰软件学院
  16. 米的换算单位和公式_米的单位换算公式大全(长度单位大全表)
  17. 5.Flink对接Kafka入门
  18. RabbitMQ消息队列工作原理及集成使用
  19. VB让图片铺满整个FORM
  20. uniapp H5、app、小程序不同端之间跳转

热门文章

  1. 第2章 C语言的数值数据与非数值数据 (二)
  2. 认真学习数据结构之B/B+/B*树
  3. 曲率(Curvature)
  4. 加强计算机管理,浅谈如何加强高校计算机专业管理
  5. np.savetxt保存时数据不使用科学计数法形式
  6. 实现自己的日志打印系统
  7. latex论文排版初级应用
  8. Flask之钩子函数
  9. JAVA知识整理(一)
  10. 理解GloVe模型(+总结)