Spring MVC 实现原理
为什么80%的码农都做不了架构师?>>>
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring*.xml</param-value>
</context-param>
<listener><listener>org.springframework.web.context.ContextLoaderListener</listener>
</listener><servlet><servlet-name>test</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath*:config/test-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping><servlet-name>test</servlet-name><url-pattern>/</url-pattern>
</servlet-mapping>
从这个配置里面看见,一个配置上下文的监听器,这个监听器负责整个 IOC 容器 在 Web 环境中的启动工作,另外一个是配置 SpringMVC 的分发请求器。他们共同构成了 Spring 和 Web 容器的接口操作,他们与 Web容器的 耦合 是通过ServletContext 初始化的,而DispatcherServlet就负责 Web 请求转发的建立,完成 http 的请求响应。
在这个启动过程中可以看见系统加载是依赖 web 容器的 ServletContextListener 来触发的,这个Listener的触发会在如下时候:
当 Servlet 容器启动或终止 Web应用时,会触发 ServletContextEvent 事件,该事件由ServletContextListener 来处理。在 ServletContextListener 接口定义了处理 ServletContextEvent 事件的两个方法。
- contextInitialized( ServletContextEvent sce): 当 Servlet容器启动Web应用的时,调用该方法;调用完成之后,容器在对 Filter 初始化,并且对那些在 Web应用启动时就需要被初始化的 Servlet 进行初始化。
- contextDestroyed( ServletContextEvent sce) : 当Servlet容器终止 Web应用时候调用该方法;在调用该方法之前,容器会销毁所有的 Servlet 和 Filter。
在 Spring 会在 Web容器启动的过程中,借助这个监听器来创建它的上下文,而这个上下文其实就是 IOC 容器的初始化过程。而这个上下文初始化的过程同时也会把这个 ServletContext 给设置上,以供后面的 WebApplicationContext 来获取 Web容器级别的全局属性。
先看下这个创建的 XmlWebApplicationContext 上下文的类继承关系:
它的 refresh 过程其实是在 AbstractApplicationContext 完成的,如下代码:
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}}}
这个就是之前 spring ioc 中已经讲到过的容器启动过程,在 XmlWebApplicationContext它重写了 beanDefinition 的加载,如下代码
/*** Loads the bean definitions via an XmlBeanDefinitionReader.* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader* @see #initBeanDefinitionReader* @see #loadBeanDefinitions*/@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);// Configure the bean definition reader with this context's// resource loading environment.beanDefinitionReader.setEnvironment(getEnvironment());beanDefinitionReader.setResourceLoader(this);beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));// Allow a subclass to provide custom initialization of the reader,// then proceed with actually loading the bean definitions.initBeanDefinitionReader(beanDefinitionReader);loadBeanDefinitions(beanDefinitionReader);}
对于这个实现类它主要添加了对 web 环境 和 xml配置类的定义处理,例如:
/** Default config location for the root context */public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";/** Default prefix for building a config location for a namespace */public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";/** Default suffix for building a config location for a namespace */public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
这三个静态的定义就是专门为 web 环境来设置的,相对于配置资源的获取从以下这段重写的代码可以看出:
/*** The default location for the root context is "/WEB-INF/applicationContext.xml",* and "/WEB-INF/test-servlet.xml" for a context with the namespace "test-servlet"* (like for a DispatcherServlet instance with the servlet-name "test").*/@Overrideprotected String[] getDefaultConfigLocations() {if (getNamespace() != null) {return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};}else {return new String[] {DEFAULT_CONFIG_LOCATION};}}
在 启动时序中 有一个 initWebApplicationContext 的过程,这个过程里面有如下一段代码可以简单的说明一下:
if(this.context == null){this.context = createWebApplicationContext(servletContext);
}
也就是 context 创建过程,这个 createWebApplcationContext 的如下实现:
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {Class<?> contextClass = determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() +"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");}return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}
在创建 WebApplicationContext 的时候这里面有一个选择上下文 class 的方法:
protected Class<?> determineContextClass(ServletContext servletContext) {String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);if (contextClassName != null) {try {return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());}catch (ClassNotFoundException ex) {throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", ex);}}else {contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());try {return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());}catch (ClassNotFoundException ex) {throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", ex);}}}
首先会判断在 web 容器的上下文全局属性里面没有做设置,如果做了设置就使用这个类。如果没有设置就从一个默认的策略 properties 里面去获取这个配置,这个配置的默认文件内容如下:
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
也就是说 spring 的 MVC 默认上下文就是 XmlApplicationContext ,验证了对这个类的分析。
转载于:https://my.oschina.net/exit/blog/812688
Spring MVC 实现原理相关推荐
- Spring MVC工作原理
转载自 Spring MVC工作原理 Spring MVC框架介绍 Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring M ...
- spring Mvc 执行原理 及 xml注解配置说明 (六)
Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 ...
- Spring Mvc工作原理图解
Spring Mvc工作原理图解 先来一张图: 目前还是有些疑惑,因为是初学 思考了大半天,整理了初步的一些工作原理: 如图上所述: 1.用户(打开网站,输入网址url)发送请求. 2.用户的请求会通 ...
- Spring Boot Spring MVC异常处理原理分析
一.Spring MVC为处理异常的前期准备 DispatcherServlet 入口类,是一个Servlet,是所有请求的分发点 初始化 DispatcherServlet在初始化时会触发onRef ...
- Spring MVC工作原理 及注解说明
转载自 http://blog.csdn.net/shuyeshangdemayi/article/details/50259493 SpringMVC框架介绍 1) Spring MVC属于Spr ...
- 详细述说spring mvc工作原理
spring mvc是什么? springMVC是一个MVC的开源框架,springMVC=struts2+spring,springMVC就相当于是Struts2加上sring的整合,但是这里有一个 ...
- Spring mvc ContextLoaderListener 原理解析
对于熟悉Spring MVC功能,首先应从web.xml 开始,在web.xml 文件中我们需要配置一个监听器 ContextLoaderListener,如下. <!-- 加载spring上下 ...
- spring MVC运行原理
按照上边的执行流程图,我们可以看出一个SpringMVC整体的一个执行轮廓,下面我们具体来分析下 首先服务器接收到一个请求,匹配并调用了我们的前端控制器(DispatcherServlet)也叫中央处 ...
- spring mvc工作原理及组件说明
组件说明 以下组件通常使用框架提供实现: DispatcherServlet:前端控制器 用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由 ...
最新文章
- 精选Spring Boot三十五道必知必会知识点!
- recycleview 使用详解,添加头部尾部,混合item,侧滑菜单,跳转到指定位置,实现九宫格布局
- js unescape 对应php的函数,php实现Javascript的escape和unescape函数
- react中类组件this指向
- 系统新模块增加需要哪些步骤_想要吸引人流,儿童乐园需要增加哪些新设备呢...
- 拖动内容,滚动条滚动,横向
- 雷林鹏分享:PHP 表单 - 验证邮件和URL
- 19.卷1(套接字联网API)---密钥管理套接字
- gimp中文版教程_Gimp中文经典入门实用教程(合辑).pdf
- FME中GIS面分图层转为CAD填充并符号化,且图斑含面积属性
- 反激变压器结构设计学习笔记(进阶)
- 信息系统项目管理师必背核心考点(四十八)合同类型的选择
- 新一代的核心路由器的发展趋势分析
- iOS动画:粒子发射器(20)
- 9月编程排行榜新鲜出炉霸榜还得是它~
- 中断处理过程示意图_中断和中断处理流程
- git pull 与 git push 的区别
- Java-名片管理系统
- python自带sqlite_Python使用sqlite3模块内置数据库
- apktool,dex2jar,jd-gui简单使用