Spring mvc项目上下文启动流程解析
来源:互联网 发布:linux合并两个文件夹 编辑:程序博客网 时间:2024/05/14 12:56
软件开发的中,如果某些特性的使用比较普遍,那么这些特性往往可以作为平台特性来实现,通过对这些平台特性进行有效的封装,使其向其他应用开放。正是如此,spring由于其IOC、AOP、事务处理、持久化驱动等特点,使得其起到了一个应用平台的作用。Spring MVC是Spring的一个重要的模块,其web应用的实现,是由Spring的来支撑的,Spring MVC的是实现也是依托再Spring平台提供的基础特性的。本文主要是介绍Spring mvc容器初始化的过程,从中可以看出Spring MVC的对于Spring的依赖。
一、从Web应用角度看Spring MVC
在Servlet模型中,请求-响应的实现依赖于两大元素的共同配合:
1. 配置Servlet及其映射关系(在web.xml中)
2. 在Servlet实现类中完成响应逻辑
项目规模扩大之后,请求-响应的映射关系全部定义在web.xml中,将造成web.xml的不断膨胀而变得难以维护。针对这个问题,SpringMVC提出的方案就是:提炼一个核心的Servlet覆盖对所有Http请求的处理。这一被提炼出来的Servlet,通常被我们称之为:核心分发器。在SpringMVC中,核心分发器就是org.springframework.web.servlet.DispatcherServlet。
核心分发器要解决的是下面两个问题:
问题1:核心Servlet应该能够建立起一整套完整的对所有Http请求进行规范化处理的流程。
问题2:核心Servlet应该能够根据一定的规则对不同的Http请求分发到不同的Servlet对象上去进行处理。
针对上面的这个两个问题,SpringMVC的解决方案是:将整个处理流程规范化,并把每一个处理步骤分派到不同的组件中进行处理。
处理流程规范化 :将处理流程划分为若干个步骤(任务),并使用一条明确的逻辑主线将所有的步骤串联起来
处理流程组件化 : 将处理流程中的每一个步骤(任务)都定义为接口,并为每个接口赋予不同的实现模式
处理流程规范化的首要内容就是考虑一个通用的Servlet响应程序大致应该包含的逻辑步骤:
- 对Http请求进行初步处理,查找与之对应的Controller处理类(方法)
- 调用相应的Controller处理类(方法)完成业务逻辑
- 对Controller处理类(方法)调用时可能发生的异常进行处理
- 根据Controller处理类(方法)的调用结果,进行Http响应处理
所谓的组件化,实际上也就是使用编程语言将这些逻辑语义表达出来。在Java语言中,最适合表达逻辑处理语义的语法结构是接口,而接口可以有不同的实现,因此上述的四个流程也就被定义为了四个不同接口,它们分别是:
- HandlerMapping
- HandlerAdapter
- HandlerExceptionResolver
- ViewResolver
二、从Spring角度看Spring MVC
从上面可以看出,组件是核心分发器(DispatchServlet)的核心所在,它们是http请求处理的逻辑载体,DispatcherServlet是逻辑处理的调度中心,组件则是被调度的操作对象。而Spring容器在这里所起到的作用,是协助DispatcherServlet更好地对组件进行管理。
我们知道,SpringMVC的组件是一个个的接口定义,当我们在SpringMVC的核心配置文件中定义一个组件时,使用的却是组件的实现类,用具体的实现类来指定组件的行为模式,不同的实现类代表了不同的行为模式,它们在Spring中是可以共存的。Spring容器对这些实现类进行管理,具体如何使用,由应用程序本身来决定。
上图是Spring官方reference中的一幅图,DispatchServlet对外接收http的请求,而请求的处理的是依靠组件来完成的,组件的接口实现的是依靠Spring IOC容器(WebApplicationContext)来管理。从这个图中我们可以看出,Spring MVC实现web应用是依赖与Spring提供的基础特性(IOC等)。图中的两个WebApplicationContext的区别,留到下面再讲。
三、Spring MVC 入口配置文件web.xml
Spring mvc 有哪些配置文件:
- 入口配置文件:web.xml;由web或应用服务器为每个web项目加载的配置文件。
- 应用上下文:包括web框架特有配置文件:SpringMVC的${dispatcherServletName}-servlet.xml配置文件。和Spring的配置文件applicationContext.xml,applicationContext-*.xml。
遵循servlet规范,Spring MVC的web应用的入口配置文件也是web.xml。web容器的初始化首先是加载web.xml文件,Jetty在启动时首先加载此配置文件,并且对其中定义的listener和servlet等进行相应的加载和初始化。Jetty并不清楚(也不关心)其他配置文件的存在,因此,加载其他配置文件应该是你(框架)的事情。那么怎么加载呢?前面说过Jetty在启动时会自动加载和初始化listener和servlet,那么我们可以自定义一个listener(ContextLoaderListener)或servlet(DispatcherServlet),Jetty会根据web.xml加载和初始化他们,而他们则负责加载相应的配置文件。
在web.xml配置文件中,有两个主要的配置:ContextLoaderListener和DispatcherServlet。同样的关于spring配置文件的相关配置也有两部分:context-param和DispatcherServlet中的init-param。那么,这两部分的分别表示是Spring 容器的初始化和web容器的初始化。DispatcherServlet和ContextLoaderListener提供了在Web容器中对spring的接口。ServletContext为Spring的IOC容器提供了一个宿主环境,在宿主环境中,Spring MVC建立起了一个IOC容器体系。
如果项目中不使用webapplicationconext,可以不用配置contextLoadListener进行监听。
下面看一下Spring mvc 中web.xml文件的相关配置内容:
四、Spring IOC容器(根上下文)的初始化
Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext接口扩展ApplicationContext,使得拥有web功能,WebApplicationContext接口默认的实现是XmlWebApplicationContext。那么,Spring MVC是如何在web环境中创建IoC容器呢?
先看一下WebApplicationContext的源码,
WebApplicationContext
在Spring MVC中,Spring Context是以父子的继承结构存在的。Web环境(ServletContext)中存在一个根上下文,这个Context是整个应用的根上下文,是其他context的双亲Context。同时Spring MVC也对应的持有一个独立的Context,它是根上下文的子上下文。
由ContextLoaderListener首先启动的上下文为根上下文,该上下文是与ServletContext相伴而生的,在根上下文的基础上,Spring MVC对应持有的一个用来管理控制器需要的对象的子上下文。下图是ContextLoaderListener继承关系,它实现了ServletContextListener接口,这个接口提供了与Servlet生命周期结合的回调,比如contextInitialized和contextDestroyed方法。建立WebApplicationContext的过程是在contextInitialized的接口实现中完成的,具体的载入IOC容器的过程是由ContextLoader来完成的。
ContextLoaderListener
从ContextLoaderListener源码可以看出,实现的是ServletContextListener接口,这个接口里的函数会结合Web容器的生命周期被调用。因为ServletContextListener是ServletContext的监听者,当servletContext启动或者停止的时候,会触发响应的事件,监听器ServletContextListener会接收到事件,会做出相应的响应,比如这里的contextInitialized方法和contextDestroyed方法。Spring IOC容器(根上下文)的生成与销毁就是通过这个两个方法的,所以根上下文是与ServletContext相伴而生的。
所以当Web应用启动时,contextInitialized方法会执行载入根上下文(IOC容器),具体过程是首先从Servlet事件中得到ServletContext,然后以ServletContext为宿主环境,载入根上下文(IOC容器),具体的载入过程是由ContextLoader处理的。
下图所示为根上下文的加载过程,下面将结合源码来看一下这个过程是如何实现的。
根上下文的载入过程:
ROOT Context是在ContextLoaderListener中配置的,ContextLoaderListener读取context-param中的contextConfigLocation指定的配置文件,创建ROOT Context。下面看一下ContextLoaderListener中创建context的源码:
ContextLoader加载根上下文的源码
从上面的源码中可以看出来,IOC容器在web容器中的启动过程,与在应用中启动IOC容器的方式相似,不同的是这里需要考虑web容器的环境的特点,比如各种参数的设置,IOC容器与web容器ServletContext的结合等。在初始化上下文以后,该上下文被存储再ServletContext中,这样就建立了一个全局的关于整个应用的上下文,即所谓的根上下文。同时在启动Spring MVC的时候,DispatchServlet在进行自己持有的上下文的初始化时,是将此根上下文设置为自己的双亲上下文的。
http://blog.csdn.net/and1kaney/article/details/51214193 这篇文章可以看到根容器初始化过程的整个的call hierarchy。
五、Spring MVC容器(子上下文)的初始化
以上是web容器中根上下文的加载与初始化,在完成对ContextLoaderListener的初始化以后,web容器开始初始化DispatchServlet,DispatchServlet会建立自己的上下文来管理Spring MVC的bean对象。在建立这个自己持有的上下文的时候,会从ServletContext中得到根上下文作为DispatchServlet持有的上下文的双亲上下文,再对自己持有的上下文进行初始化,最后把自己持有的这个上下文也保存到ServletContext中。
我们先看下DispatchServlet的继承关系,如下图。DispatchServlet通过继承FrameworkServlet和HttpServletBean而继承了HttpServlet。HttpServletBean是Spring对于Servlet最低层次的抽象。在这一层抽象中,Spring会将这个Servlet视作是一个Spring的bean,并将web入口配置文件web.xml中DispatchServlet定义的init-param参数中的值作为bean的属性注入进来。
DispatcherServlet也是一个Servlet,根据Servlet规范的定义,Servlet中的两大核心方法init方法和service方法:
1. init方法
在整个系统启动时运行,且只运行一次。因此,在init方法中我们往往会对整个应用程序进行初始化操作。这些初始化操作可能包括对容器(WebApplicationContext)的初始化、组件和外部资源的初始化等等。
2. service方法
在整个系统运行的过程中处于侦听模式,侦听并处理所有的Web请求。因此,在service及其相关方法中,我们看到的则是对Http请求的处理流程。
这篇文章主要是介绍Spring mvc 容器的初始化,所以主要是介绍iDisipatchServlet的init方法。
FrameworkServlet则是在HttpServletBean的基础之上的进一步抽象。通过FrameworkServlet真正初始化了一个Spring的容器(WebApplicationContext),并引入到Servlet对象之中:
FrameworkServlet
在这个调用关系中,可以看到MVC的初始化是再DispatchServlet的initStrategies方法中完成的,包括对各种MVC框架的实现元素,比如支持国际化的LocaleResolver、支持request映射的HandlerMappings、以及视图生成的ViewResolver等的初始化。对于具体实现元素的初始化就不一一列出源码了,这里以HandlerMappings为例来说明MVC框架元素的初始化过程。
DispatchServlet
六、Spring MVC 上下初始化流程图
- Spring mvc项目上下文启动流程解析
- Spring MVC流程解析
- Spring MVC解析视图流程
- Spring MVC+Hibernate框架项目开发流程
- 项目启动失败 no mapped spring-mvc
- spring MVC项目启动报错
- spring mvc 双亲上下文问题
- spring mvc 获取上下文路径
- Spring MVC上下文父子容器
- Spring mvc 上下文初始化过程
- Spring MVC Web应用上下文
- spring mvc 获取上下文路径
- Spring MVC入门-项目搭建步骤解析
- Spring MVC 根应用上下文在Web容器中的启动及其销毁
- Spring MVC 系列(一)——Spring MVC核心组件及工作流程解析
- Spring MVC 系列(一)——Spring MVC核心组件及工作流程解析
- spring MVC 工作流程
- Spring MVC流程
- 创建线程的一种方法
- 树结构练习——判断给定森林中有多少棵树(简单并查集)
- 机器学习实战--第三版代码修改
- Python使用phantomJS实现自动登录
- Canvas实现多个圆形进度条显示百分比,并绑定各自的click事件
- Spring mvc项目上下文启动流程解析
- js添加、移除、移动、复制、创建和查找节点
- 做表要点
- <h1>测试博客</h1><script type="text/javascript">alert(456);</script>
- Shader 遮罩纹理贴图参考代码笔记
- Dubbo架构设计详解
- socket编程之解决流协议的粘包问题(二)
- jQuery 监听修改文本框事件
- windows开机后一键启动应用程序