SpringMVC——DispatcherServlet的IoC容器(Web应用的IoC容器的子容器)创建过程
在上一篇《Spring——Web应用中的IoC容器创建(WebApplicationContext根应用上下文的创建过程)》中说到了Web应用中的IoC容器创建过程.这一篇主要讲SpringMVC的核心DispatcherServlet.
从web.xml中简要回顾一下WebApplicationContext根应用上下文的创建过程.具体过程详见上篇博客.
<!--WebApplicationContext配置参数-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
<!--注册ContextLoaderListener,加载根应用上下文-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
DispatcherServlet实际上就是一个Servlet所以它在web.xml中的配置和普通的servlet没有区别.
<!--注册DispatcherServlet,加载应用上下文-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-servlet.xml</param-value> <!--若不显示添加配置文件路径,则会默认加载servlt-name的名字+"-servlet.xml"-->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--servlet映射-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
用过原生Servlet写过web都知道自定义的Servlet需要继承HttpServlet类实现doPost和doGet方法.DispatcherServlet类的主要继承关系如下:

在这篇博客中从不细讲Servlet,从HttpServletBean的开始讲起.
DispatcherServlet是什么?它为什么在SpringMVC中起到核心作用?原因很简单:所有来自客户端的请求都会经过DispatcherServlet,由DispatcherServlet将不同的请求分发至不同的Controller,所以DispatcherServlet是一个前置控制器起的是分发来自客户端请求的作用.根据不同的配置会接收不同的请求,这在web.xml中servlet映射中可体现.如果配置的是"/"则是所有请求都会经过DispatcherServlet,但通常不会这么做,比如一些静态资源就不必经过DispatcherServlet.
首先大致了解一下Servlet.Web容器接收到来自客户端不同类型(post,get等)的时候,实际上是所有的请求都是访问Servlet接口的service方法,在HttpServlet抽象类中实现了service方法,在service方法中判断是哪种具体的请求,再将不同的请求分发至不同的处理方法.
用原生的Servlet编写的Web应用通常是继承HttpServlet方法,重写doGet和doPost方法.由于DispatcherServlet在SpringMVC中责任重大,作为一个前端控制器,所有的Web请求都需要通过它处理,进行转发,匹配,数据处理后,并转由页面进行展现.可以看到DispatcherServlet并没有直接继承HttpServlet,而是HttpServletBean.在Servlet初始化过程中,Servlet的init方法会被调用,而Servlet提供的API中init方法没有做任何事,也就是说我们可以通过重写init方法来实现我们自己的业务逻辑.
//GenericServlet.java
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
...
public void init() throws ServletException { }
...
在HttpServletBean重写了init方法,并且不能被其子类所重写.
//HttpServletBean.java
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
} // Set bean properties from init parameters.从初始化参数中设置bean属性
try {
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
} // Let subclasses do whatever initialization they like.调用子类的initServletBean进行具体的初始化
initServletBean(); if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
...
//具体的初始化交由子类去完成,即FrameworkServlet
protected void initServletBean() throws ServletException {
}
顺着初始化这条线我们来到FrameworkServlet.照猫画虎,它重写了父类的initServletBean,但同样将它置为不能被其子类所重写.
//FrameServlet.java
protected final void initServletBean() throws ServletException {
getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
if (this.logger.isInfoEnabled()) {
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
}
long startTime = System.currentTimeMillis(); try {
this.webApplicationContext = initWebApplicationContext(); //在这里不是初始化Spring根应用上下文(Web应用的IoC容器),而是初始化SpringMVC的Servlet上下文创建自己所持有的IoC容器.如果没有则调用createWebApplicationContext方法进行创建.并将根应用上下文作为它的双亲上下文
initFrameworkServlet(); //此方法也没有给出具体实现,再其子类DispatcherServlet也没有对它重写.
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
} if (this.logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
...
//在所有的bean配置参数和WebApplicationContext被加载后会调用此方法,默认实现为空,它的子类可以重写此方法来实现需要的初始化操作.子类DispatcherServlet并没有重写.
protected void initFrameworkServlet() throws ServletException {
}
简单回顾一下整个初始化过程(一个不规范的图)

以上部分只是简要的说明了一下DispatcherServlet的IoC容器初始化过程,但还是没有说明一个请求是如何在DispatcherServlet做到分发到不同Controller的.
在DispatcherServlet类中有一个initStrategies方法,在这个方法中初始化整个SpringMVC框架的初始化,包括其中的http请求映射关系:
//DispatcherServlet.java
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context); //这里就是为http请求找到相应的Controller控制器
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
容易得知,initStrategies方法是在onRefresh方法中调用的,FrameworkServlet没有对onRefresh做任何有意义的实现,而是交由它的子类DispatcherServlet去完成.在FramworkServlet的initWebApplicationContext方法中完成了对它的调用.所以再次回到FramworkServlet的initWebApplicationContext方法,只截取其中一段:
//FrameworkServlet.java
protected WebApplicationContext initWebApplicationContext() {
......
if (this.webApplicationContext != null) {
......
configureAndRefreshWebApplicationContext(cwac); //在此方法中调用的onRefresh
......
}
if (wac == null) {
wac = createWebApplicationContext(rootContext); //此方法中最后也是调用的configureAndRefreshWebApplicationContext方法
} if (!this.refreshEventReceived) {
onRefresh(wac);
}
......
return wac;
}
更为具体的SpringMVC处理http分发请求,我们再下一篇中再来详细讲解initStrategies中的initHandlerMappings.
SpringMVC——DispatcherServlet的IoC容器(Web应用的IoC容器的子容器)创建过程的更多相关文章
- Spring父容器与子容器
在使用spring+springMVC的web工程中,我们一般会在web.xml中做如下配置: <context-param> <param-name>contextConfi ...
- spring之:XmlWebApplicationContext作为Spring Web应用的IoC容器,实例化和加载Bean的过程
它既是 DispatcherServlet 的 (WebApplicationContext)默认策略,又是 ContextLoaderListener 创建 root WebApplicationC ...
- SpringMVC DispatcherServlet 说明与web配置
使用Spring MVC,配置DispatcherServlet是第一步. DispatcherServlet是一个Servlet,所以能够配置多个DispatcherServlet. Dispatc ...
- 这一次搞懂Spring Web零xml配置原理以及父子容器关系
前言 在使用Spring和SpringMVC的老版本进行开发时,我们需要配置很多的xml文件,非常的繁琐,总是让用户自行选择配置也是非常不好的.基于约定大于配置的规定,Spring提供了很多注解帮助我 ...
- springmvc.xml,context.xml和web.xml
1:springmvc.xml配置要点 一般它主要配置Controller的组件扫描器和视图解析器 下为:springmvc.xml文件 <?xml version="1.0" ...
- java maven、springmvc、mybatis 搭建简单Web项目学习笔记
前言: 空余的时间,学学 Java,没准哪天用的到: 环境搭建折腾了好几天,总算搞顺了,也做个学习笔记,以防后面会忘记: 一.安装文件及介绍 JDK:jdk1.8.0 77 eclipse-maven ...
- 【Spring】非Spring IOC容器下获取Spring IOC上下文的环境
前言 在Spring Web项目中,有些特殊的时候需要在非Spring IOC容器下获取Spring IOC容器的上下文环境,比如获取某个bean. 版本说明 声明POM文件,指定需引入的JAR. & ...
- 对spring web启动时IOC源码研究
研究IOC首先创建一个简单的web项目,在web.xml中我们都会加上这么一句 <context-param> <param-name>contextConfigLocatio ...
- spring-framework-中文文档一:IoC容器、介绍Spring IoC容器和bean
5. IoC容器 5.1介绍Spring IoC容器和bean 5.2容器概述 本章介绍Spring Framework实现控制反转(IoC)[1]原理.IoC也被称为依赖注入(DI).它是一个过程, ...
随机推荐
- javaweb浏览器随机输出一张验证码图片
一.在web.xml中的配置如下: <?xml version="1.0" encoding="UTF-8"?><web-app xmlns: ...
- 老李分享: JSON
老李分享: JSON poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478, ...
- 老李秘技:loadrunner回放脚本错误提示Error: "HTTP Status-Code 500"
老李秘技:loadrunner回放脚本错误提示Error: "HTTP Status-Code 500" 当脚本回放的时候出现错误提示Error: "HTTP Sta ...
- asp.net core源码飘香:从Hosting开始
知识点: 1.Kestrel服务器启动并处理Http请求的过程. 2.Startup的作用. 源码飘香: 总结: asp.net core将web开发拆分为多个独立的组件,大多以http中间件的形式添 ...
- UIScrollView的布局
一.UIScrollView的子控件布局不能跟其它的控件一样进行布局,因为UIScrollView会根据子控件计算出ContentSize的大小,那么我们应该如何进行布局呀. 遵循以下两点就行 1.参 ...
- angular中路由的实现(针对新手)
最近搜了一下网上的教程,看完总感觉有点糊涂,对于新手来说可能云里雾里,所以写一个最简单的路由来给大家做个指引. 首先当然需要准备angular,下载地址:https://angular.io/ 现在a ...
- es6面试问题——Promise
话说刚换工作一个月有余,在上家公司干的实在是不开心,然后就出来抱着试试的心态出来面了几家公司,大多数公司问的前端问题也就那么多,其中有个面试问题让我记忆犹新,只因为没有答上来,哈哈! 当时面试官问我怎 ...
- C#总结(二)事件Event 介绍总结
最近在总结一些基础的东西,主要是学起来很难懂,但是在日常又有可能会经常用到的东西.前面介绍了 C# 的 AutoResetEvent的使用介绍, 这次介绍事件(event). 事件(event),对于 ...
- 使用 PHPStorm + Xdebug 实现断点调试(二)
一.配置 Xdebug 配置 Xdebug 相关参数,在 php.ini 文件中新增如下配置,如果没安装的,请参考<PHP 安装 Xdebug扩展>: [xdebug] xdebug.re ...
- C语言精要总结-指针系列(一)
考虑到指针内容繁多,这里将指针作为一个系列,从简入繁,一点一点深挖并掌握这C语言的精华.初步计划如下 此文为指针系列第一篇: C语言精要总结-指针系列(一) 内存与地址 我们可以把内存看做一排连续的房 ...