前言
Web环境是Spring框架的重要应用场景,而SpringMVC又是Web开发中一个常用的框架,因此我们有必要学习一下SpringMVC的实现原理。
回到Web项目的配置文件web.xml中,在使用SpringMVC时我们需要进行如下的配置:
1 | <servlet> |
熟悉Spring的同学对以上的配置肯定不陌生,这里配置了一个DispatcherServlet,这个Servlet是由Spring实现的,是SpringMVC最核心的部分,如上配置的这个Servlet会接收所有的请求,最终将请求分发至对应的Controller进行处理,下面我们就从DsipatcherServlet入手,学习SpringMVC的实现。
源码学习
首先,来看一看DsipatcherServlet的类继承关系(省略了部分接口):
从上图中可以看到,DispatcherServlet间接继承了HttpServlet,可用于处理Http请求。
既然DispatcherServlet也是Servlet家族中的一员,那么它肯定要遵循Servlet的生命周期,即:
- 初始化阶段,调用init()方法
- 响应客户请求阶段,调用service()方法
- 销毁阶段,调用destroy()方法
有了这些了解,我们就可以顺着DispatcherServlet的生命周期来学习SpringMVC的实现了。
初始化阶段 -> init()
首先,定位到初始化阶段,在这个阶段会调用init()方法,这个方法定义在Serlvet接口中,我们可以发现这个方法的最终实现在DispatcherServlet的父类HttpServletBean中,这个方法被定义为final方法,不可被子类覆盖,代码如下:
1 | public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { |
在上面的代码中,首先获取了init parameters,也就是web.xml中的
1 | public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { |
上面的代码中,取得了一个应用上下文,作为了根IOC容器的子容器,这样,DispatcherServlet中的IOC容器就建立起来了,细心的同学会发现,在返回应用上下文之前调用了onRefresh(wac)方法,这个方法由其子类DispatcherServlet实现,用于初始化Web层需要的策略,下面让我们一起来看一看这部分的源码:
1 | public class DispatcherServlet extends FrameworkServlet { |
从上面的代码中可以看到,在获取应用上下文的过程中初始化了DispatcherServlet中需要的各种解析器,其中包括文件解析器、区域解析器、主题解析器等。
解析器的初始化过程大体相同,都是从应用上下文中取得相应的Bean,若不存在则使用默认解析器策略。
具体关于各解析器的介绍大家可以参考一篇博客:SpringMVC解析器
到这里,DispatcherServlet的初始化阶段就完成了,在这个过程中,一方面创建了DispatcherServlet的IOC容器,并将这个IOC容器作为根IOC容器的子容器,另一方面,初始化了DispatcherServlet需要的各种解析策略,接下来,DispatcherServlet将会在处理HTTP请求时发挥重要的作用。
响应客户请求 -> service()
我们知道Servlet在接收到客户请求后会调用service()方法,根据请求类型执行doGet、doPost等一系列方法,在DispatcherServlet的继承体系中,由DispatcherServlet的父类FrameworkServlet重写了HttpServlet中的service()方法以及doGet()、doPost() 等一系列方法,下面以常用的HTTP请求方法来看一看FrameworkServlet的主要实现代码:
1 | public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { |
从上面的代码中可以看到, DispatcherServlet接收到用户请求后,会调用父类FrameworkServlet中的service()方法,最终根据请求类型调用FrameworkServlet中重写的doGet、doPost等方法,这些方法都调用了processRequest()方法,下面让我们看一下processRequest()的具体实现:
1 | public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { |
在上面的代码中我们可以看到一个用于处理请求的核心方法:doService(request, response),这个方法是一个模板方法,由其子类DispatcherServlet实现,代码如下:
1 | public class DispatcherServlet extends FrameworkServlet { |
doService方法比较简单,主要是为request设置一些必要的属性,接下来调用了doDispatch方法进行请求的分发,这是SpringMVC中的核心功能,doDispatch方法中主要进行了如下的处理:
- 处理拦截
- 处理请求
- 解析View
代码如下:
1 | public class DispatcherServlet extends FrameworkServlet { |
到这里,客户的请求就相应完成了。在这个过程中,首先处理匹配的处理器中的拦截器,然后通过处理器处理客户的请求,最后通过视图解析器解析和渲染视图,这里还有许多细节未深入分析,我们将在后续继续学习。
销毁阶段 -> destroy()
Servlet的销毁阶段会调用destroy()方法,这个方法的实现在FrameworkServlet中,实现比较简单,就是将Servlet中的IOC容器关闭,代码如下:
1 | public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { |
总结
本篇中,顺着Servlet的生命周期大致分析了SpringMVC的核心类DispatcherServlet的实现,对SpringMVC的请求控制有了一定的了解,但在DispatcherServlet处理客户请求的部分有许多内容未深入分析,需要进一步学习。
参考资料:《Spring技术内幕》
最后的最后,安利一下自己写的一个Java代码生成工具,能够方便的生成Spring、SpringMVC、Mybatis架构下的Java代码,希望能对大家有所帮助,地址:Java代码生成器:Generator