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. 借腾讯开源 VasDolly,谈谈 Android 签名和多渠道打包的原理!

    一.前言 Hi,大家好,我是承香墨影! 当我们需要发布一款 App 到应用市场的时候,一般需要我们针对不同的市场生产不同的渠道包,它们使用的是同一套代码,只是会包含一些各自的渠道信息,用于我们做数据分 ...

  2. js “top、clientTop、scrollTop、offsetTop…”

    当要做一些与位置相关的插件或效果的时候,像top.clientTop.scrollTop.offsetTop.scrollHeight.clientHeight.offsetParent...看到这么 ...

  3. FLEX类似谷歌地图拖拽功能

    要实现类似于谷歌地图拖拽功能,可以用s:Scroller标签来实现,代码如下: mxml: <s:Scroller width="100%" height="100 ...

  4. CentOS 6安装Oracle报错解决方案

    1. Preparing to launch Oracle Universal Installer from /tmp/OraInstall2017-05-23_04-18-48AM. Please ...

  5. 由select引发的思考

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

  6. HDU - 1241 dfs or bfs [kuangbin带你飞]专题一

    8个方向求联通块,经典问题. AC代码 #include<cstdio> #include<cstring> #include<algorithm> #includ ...

  7. SpringBoot整合Mybatis,多数据源,事务,支持java -jar 启动.

    用了一段时间SpringBoot,之前配置MYBATIS ,在打包WAR 放到tomcat下正常,但是WAR已经过时了,现在流行直接打包JAR 丢到DOCKER 里,无奈JAR 启动的时候MAPPER ...

  8. Android使用百度地图出现闪退及定位时显示蓝屏问题

     目录 1.Android使用百度地图出现闪退 2.Android使用百度地图定位出现蓝屏问题     1.Android使用百度地图出现闪退 一般情况下出现闪退是在AndroidManifest.x ...

  9. H3C虚拟化之IRF

    SA system-view irf domain 10 irf member 1 ren 1 y int ten 1/0/50 shu qu irf-port 1/1 port group int ...

  10. Linux传统Huge Pages与Transparent Huge Pages再次学习总结

      Linux下的大页分为两种类型:标准大页(Huge Pages)和透明大页(Transparent Huge Pages).Huge Pages有时候也翻译成大页/标准大页/传统大页,它们都是Hu ...