Spring MVC原理

针对有Java Web基础、Spring基础和Spring MVC使用经验者。

前言

目前基于Java的web后端,Spring生态应该是比较常见了。虽然现在流行前后端分离,MVC和后端模板渲染越来越少,后端专注向前端提供数据接口。但由于笔者维护着一个老项目,既有JSP技术也有只返回JSON的接口,两者都是基于Spring MVC这一套技术实现的,所以暂且觉得了解一下Spring MVC原理还是有所裨益的。

Spring MVC工作流

想必大家第一次学习Spring MVC时都见过这张图

看完这张图,Spring MVC的工作流基本是一目了然了。建好工程然后web.xml里配个DispatcherServlet(甚至连web.xml都不需要配置,直接通过Java类和@Configuaration进行配置),注解@Controller, @RequestMapping, @Service等等一顿注解搞起来,在IDE中把Tomcat配好,OK,一个Spring MVC的Hello World就跑起来了。问起Spring MVC的原理,我也能按着上图工作流巴拉几句。

然而,与其说以上是Spring MVC的原理不如说是MVC的模型。Spring MVC怎么就知道把一个请求路由到对应Controller中方法的呢?方法返回了一个ModelAndView对象甚至是一个视图名String,框架带着Model和视图名找到视图(比如最常见的jsp)后怎么搞呢?半路出家的笔者来,可以说是相当好奇了。

从servlet、web.xml和WEB-INF说起

Servlet

Java的Servlet我就不赘述了,直接看类的注释

A servlet is a small Java program that runs within a Web server.Servlets receive and respond to requests from Web clients, usually across HTTP

Servlet只是一个规范,必须部署到Servlet容器中才能工作,当然本文说的肯定是HttpServlet,所以常用的容器也就是Tomcat、Jetty等。

先看Servlet接口,每个方法的注释请参见源码

public interface Servlet {

    public void init(ServletConfig config) throws ServletException;

    public ServletConfig getServletConfig();

    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    public String getServletInfo();

    public void destroy();
}

其中init方法在Servlet准备对外提供服务时被容器调用,并且整个生命周期中只调用一次,destroy方法当然就是结束时调用了,service方法处理ServletRequest并响应。

web.xml

上面说到把Servlet部署到Servlet容器中后,Servlet就可以接受请求了,那容器怎么知道哪个请求对应哪个Servlet?

OK,我们的web.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_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>com.foo.bar.SomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>/some/url</url-pattern>
</servlet-mapping>
</web-app>

如上,最简单的一个web.xml描述文件,描述了什么呢?应该都懂,SomeServlet这个Servlet会处理URL为/some/url的请求,这个SomeServlet大概长这样

public class SomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.write("hello boys");
writer.flush();
writer.close();
}
}

GET someHost:port/some/url时,就会返回hello boys了。不难想象,请求多的话,得在web.xml中servlet的节点将越来越多,维护起来也是个体力活儿(当然用xml维护的Spring MVC配置文件也没少多少,不过维护起来轻松一些,因为结合了Spring bean,下面再讲)。

以上应该是对Servlet相关最简单的描述了。

Spring容器管理bean

这个用过没用过Spring的应该都有所了解,说一下我自己的理解

核心就是DI,通过Spring这个IOC容器来管理各个Bean之间的依赖关系,通过Spring在启动时来注入依赖,而不是在写代码时就new出来。

这里面我觉得比较重要的几个类,也是我认为看Spring代码时比较好串联起来的几个类:

  • BeanDefinition: Spring的定义,最常见的我个人认为最好理解的也就是Xml中定义的bean,此处膜拜一下Spring预留的扩展点,要不然dubbo的bean怎么能通过Spring容器管理呢对吧,此处以后再说。
  • BeanFactory: 好理解,产生Bean的工厂,不多说自己看代码。
  • ApplicationContext: Spring的上下文容器,基本用的就是它,暂时把它当成黑箱,所有的bean从这里getBean获取就行了,其余自行看代码。

DispatcherServlet

好,终于到Spring MVC了,先上一个大家都见过的web.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_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</webapp>

注意到几个点:

  • DispatcherServlet这个servlet接管了所有的请求(servlet-mapping的配置)
  • servlet配置里还有个load-on-startup,且值为1
  • init-param这里配置了一个参数contextConfigLocation,其值就是Spring bean的配置文件

DispatcherServlet接管了所有请求,OK,看到这里大家估计也都明白了,是在这个servlet里的service方法里根据不同url找到不同的controller来处理的;load-on-startup这个参数规定,如果值大于0,会在启动时由容器初始化,并且值越小初始化顺序越靠前;init-param名字已经很直白了,表示这个servlet可以配置的参数,对该servlet可见(对应的还有个context-param,对所有servlet可见,web.xml里还有其他一些可配置的参数,有兴趣可以自行查阅),contextConfigLication的值就是多个定义bean的xml配置文件。

讲完这些,大家猜应该八九不离十了,总结起来就是一句话:

Servlet容器启动时调用DispatcherServlet中init方法,同时依托Spring,初始化所有bean,并保存一个url到handler之间的映射

至于映射关系就好定义了,xml配置、@RequestMapping,都是具体的实现。当然我这是简单粗暴的总结,里面细节性的问题都跳过了不过你自己在init方法里打个断点,debug跟一下,一步一步就摸清全部流程了。

文章比较短也比较简单,大家也可能都了解,但我觉得这几个点对理清整个流程还是有帮助的。提出的几个问题也没解答,我只能说答案都在代码里,跟一下全明白。写的不好大家也别笑,多给我提提建议,大家相互进步就OK。

Spring MVC简单原理的更多相关文章

  1. (4.1)Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  2. Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  3. Spring MVC工作原理(好用版)

    Spring MVC工作原理 参考: SpringMVC工作原理 - 平凡希 - 博客园https://www.cnblogs.com/xiaoxi/p/6164383.html SpringMVC的 ...

  4. Spring mvc系列一之 Spring mvc简单配置

    Spring mvc系列一之 Spring mvc简单配置-引用 Spring MVC做为SpringFrameWork的后续产品,Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块 ...

  5. spring Mvc 执行原理 及 xml注解配置说明 (六)

    Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...

  6. Spring mvc 简单异常配置jsp页面

    原文出处:http://howtodoinjava.com/spring/spring-mvc/spring-mvc-simplemappingexceptionresolver-example/ 这 ...

  7. Spring MVC执行原理

    spring的MVC执行原理 1.spring mvc将所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求 进行真正的处理工作. 2.DispatcherSer ...

  8. Spring MVC工作原理 及注解说明

    SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功 ...

  9. spring mvc简单介绍xml版

    spring mvc介绍:其实spring mvc就是基于servlet实现的,只不过他讲请求处理的流程分配的更细致而已. spring mvc核心理念的4个组件: 1.DispatcherServl ...

随机推荐

  1. shell 颜色控制系列

    shell脚本里,经常用的颜色控制,如下 格式:echo -e "\033[字背景颜色:文字颜色m字符串\033[0m" eg:echo -e "\033[41;36m ...

  2. String类为什么是final的

    首先我们使用new创建一个String对象的时候比如: String str=new String("123"); 这句话里面创建了两个对象,第一个在系统中创建了一个"a ...

  3. 机器学习之Adaboost (自适应增强)算法

    注:本篇博文是根据其他优秀博文编写的,我只是对其改变了知识的排序,另外代码是<机器学习实战>中的.转载请标明出处及参考资料. 1 Adaboost 算法实现过程 1.1 什么是 Adabo ...

  4. 由select引发的思考

    一.前言 网络编程里一个经典的问题,selec,poll和epoll的区别?这个问题刚学习编程时就接触了,当时看了材料很不明白,许多概念和思想没有体会,现在在这个阶段,再重新回头看这个问题,有一种豁然 ...

  5. UVA1374 IDA*

    我刚开始的思路就是:用启发函数max * pow(2 , maxd - d) < n直接去判断,两个for循环往数组延伸,找到n为止,可是速度太慢.刘汝佳大哥说的直接使用新延伸出来的数,这样确实 ...

  6. UVA1213

    先打表,再回溯+剪枝 AC代码: #include<cstdio> #include<cstring> #include<cmath> const int maxn ...

  7. 多项式A除以B

    这个问题我是在PAT大区赛题里遇见的.题目如下: 多项式A除以B(25 分) 这仍然是一道关于A/B的题,只不过A和B都换成了多项式.你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数 ...

  8. Storm业务功能

    监控平台当前使用storm对日志进行流式分析计算,用于支撑监控数据清洗,后来逐渐在storm上搭建起数据在线关联,数据离线关联,明细数据清洗,日志搜索等功能,本章节对各功能进行简要概述. 对storm ...

  9. Servlet中forward和redirect的区别(转)

    forward方式:request.getRequestDispatcher("/somePage.jsp").forwardrequest, response);     red ...

  10. Oracle SQL Developer 连接数据库如何对应数据库配置文件

    Oracle SQL Developer 连接数据库如何对应数据库配置文件 1.数据库配置文件 hibernate.connection.url jdbc:oracle:thin:@146.56.35 ...