spring mvc 总体启动流程
一、基础XML配置
1.WEB.xml配置如下
<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"><display-name>Archetype Created Web Application</display-name><!--welcome pages--><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list><!-- <listener><listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class></listener><filter><filter-name>log4jServletFilter</filter-name><filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class></filter><filter-mapping><filter-name>log4jServletFilter</filter-name><url-pattern>/*</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher><dispatcher>INCLUDE</dispatcher><dispatcher>ERROR</dispatcher></filter-mapping>--><!--配置springmvc DispatcherServlet--><servlet><servlet-name>springMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><!--配置dispatcher.xml作为mvc的配置文件--><param-name>contextConfigLocation</param-name><param-value>/dispatcher-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><!--<servlet>--><!--<servlet-name>EmpServlet</servlet-name>--><!--<servlet-class>com.gx.filter.EmpServlet</servlet-class>--><!--</servlet>--><servlet-mapping><servlet-name>springMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!--把applicationContext.xml加入到配置文件中--><context-param><param-name>contextConfigLocation</param-name><param-value>/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--<listener>--><!--<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>--><!--</listener>--><!-- <context-param>-->
<!-- <param-name>log4jConfigLocation</param-name>-->
<!-- <param-value>classpath:log4j2.xml</param-value>-->
<!-- </context-param>--></web-app>
2.applicationContext.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><context:component-scan base-package="com.tpw.service"/></beans>
3.dispatcher-servlet.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><!--此文件负责整个mvc中的配置--><!--启用spring的一些annotation --><context:annotation-config/><!-- 配置注解驱动 可以将request参数与绑定到controller参数上 --><mvc:annotation-driven><mvc:message-converters><bean class="org.springframework.http.converter.StringHttpMessageConverter"/><bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/></mvc:message-converters></mvc:annotation-driven><bean id="fastjson" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter"><property name="supportedMediaTypes"><list><value>text/html;charset=UTF-8</value><value>application/json;charset=UTF-8</value></list></property></bean><!--静态资源映射--><!--本项目把静态资源放在了webapp的statics目录下,资源映射如下--><mvc:resources mapping="/css/**" location="/static/css/"/><mvc:resources mapping="/js/**" location="/static/js/"/><mvc:resources mapping="/image/**" location="/static/images/"/><mvc:default-servlet-handler/> <!--这句要加上,要不然可能会访问不到静态资源,具体作用自行百度--><!-- 对模型视图名称的解析,即在模型视图名称添加前后缀(如果最后一个还是表示文件夹,则最后的斜杠不要漏了) 使用JSP--><!-- 默认的视图解析器 在上边的解析错误时使用 (默认使用html)- --><bean id="defaultViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/><property name="prefix" value="/WEB-INF/"/><!--设置JSP文件的目录位置--><property name="suffix" value=".jsp"/><property name="exposeContextBeansAsAttributes" value="true"/></bean><!-- 自动扫描装配 --><context:component-scan base-package="com.tpw.controller"/></beans>
二、tomcat容器引擎加载时首先加载web.xml所有配置的listener对象。\
1.我们配置的是
org.springframework.web.context.ContextLoaderListener,所有会加载此类contextInitialized方法,此方法会创建一个父类的applicationContext,加载applicationContext.xml文件中所有的扫描和配置的BEAN,并创建到容器工厂中。
@Overridepublic void contextInitialized(ServletContextEvent event) {initWebApplicationContext(event.getServletContext());}
2.然后会调用org.springframework.web.context.ContextLoader.initWebApplicationContext,创建父类applicationContext,默认为org.springframework.web.context.support.XmlWebApplicationContext类环境。
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {throw new IllegalStateException("Cannot initialize context because there is already a root application context present - " +"check whether you have multiple ContextLoader* definitions in your web.xml!");}servletContext.log("Initializing Spring root WebApplicationContext");Log logger = LogFactory.getLog(ContextLoader.class);if (logger.isInfoEnabled()) {logger.info("Root WebApplicationContext: initialization started");}long startTime = System.currentTimeMillis();try {// Store context in local instance variable, to guarantee that// it is available on ServletContext shutdown.if (this.context == null) {this.context = createWebApplicationContext(servletContext);}if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (!cwac.isActive()) {// The context has not yet been refreshed -> provide services such as// setting the parent context, setting the application context id, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent ->// determine parent for root web application context, if any.ApplicationContext parent = loadParentContext(servletContext);cwac.setParent(parent);}configureAndRefreshWebApplicationContext(cwac, servletContext);}}servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);ClassLoader ccl = Thread.currentThread().getContextClassLoader();if (ccl == ContextLoader.class.getClassLoader()) {currentContext = this.context;}else if (ccl != null) {currentContextPerThread.put(ccl, this.context);}if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime;logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");}return this.context;}catch (RuntimeException | Error ex) {logger.error("Context initialization failed", ex);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);throw ex;}}
3.创建完applicationContext后,则会contextLoader.configureAndRefreshWebApplicationContext去配置configlocation的XML,以及ID名称,然后调用applicationContext.refresh去实例化工厂中的对象。
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {if (ObjectUtils.identityToString(wac).equals(wac.getId())) {// The application context id is still set to its original default value// -> assign a more useful id based on available informationString idParam = sc.getInitParameter(CONTEXT_ID_PARAM);if (idParam != null) {wac.setId(idParam);}else {// Generate default id...wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +ObjectUtils.getDisplayString(sc.getContextPath()));}}wac.setServletContext(sc);String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);if (configLocationParam != null) {wac.setConfigLocation(configLocationParam);}// The wac environment's #initPropertySources will be called in any case when the context// is refreshed; do it eagerly here to ensure servlet property sources are in place for// use in any post-processing or initialization that occurs below prior to #refreshConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(sc, null);}customizeContext(sc, wac);wac.refresh();}
4.application.refresh,则会根据applicationContext.xml中定义去扫描或者加载实例化BEAN,这个和spring ioc 原理一样.
三、org.springframework.web.servlet.DispatcherServlet初始化
1.DispatcherServlet静态代码执行,会将DispatcherServlet.properties配置的相应工厂SPI类配置读取出来到属性列表中。
包中的配置文件路径如下:
文件内容为:
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\org.springframework.web.servlet.function.support.HandlerFunctionAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
2.会调用org.springframework.web.servlet.HttpServletBean.init 进行初始化。创建一个
BeanWrapper属性包装器,里面包装的是DispatcherServlet对象。会将web.xml中
param-name中的值设置到DispatcherServlet对象的属性包装器中,如contextConfigLocation属性设置为dispatcher-servlet.xml。
public final void init() throws ServletException {// Set bean properties from init parameters.PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);if (!pvs.isEmpty()) {try {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;}}
3.调用FrameworkServlet.initServletBean去创建子applicationContext.
protected final void initServletBean() throws ServletException {getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");if (logger.isInfoEnabled()) {logger.info("Initializing Servlet '" + getServletName() + "'");}long startTime = System.currentTimeMillis();try {this.webApplicationContext = initWebApplicationContext();initFrameworkServlet();}catch (ServletException | RuntimeException ex) {logger.error("Context initialization failed", ex);throw ex;}if (logger.isInfoEnabled()) {logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");}}
调用栈
4.初始化applicationContext时首先会获取父的applicationContext,然后会创建的子CONTEXT,
wac = createWebApplicationContext(rootContext);
org.springframework.web.servlet.FrameworkServlet
protected WebApplicationContext initWebApplicationContext() {WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;if (this.webApplicationContext != null) {// A context instance was injected at construction time -> use itwac = this.webApplicationContext;if (wac == null) {// No context instance was injected at construction time -> see if one// has been registered in the servlet context. If one exists, it is assumed// that the parent context (if any) has already been set and that the// user has performed any initialization such as setting the context idwac = findWebApplicationContext();}if (wac == null) {// No context instance is defined for this servlet -> create a local onewac = createWebApplicationContext(rootContext);}if (!this.refreshEventReceived) {// Either the context is not a ConfigurableApplicationContext with refresh// support or the context injected at construction time had already been// refreshed -> trigger initial onRefresh manually here.synchronized (this.onRefreshMonitor) {onRefresh(wac);}}if (this.publishContext) {// Publish the context as a servlet context attribute.String attrName = getServletContextAttributeName();getServletContext().setAttribute(attrName, wac);}return wac;}
5.创建新的子applicationContext,并调用其refresh方法。设置根applicationContext为父。后面的refresh就是扫描dispatch-servlet.xml中的所有配置包,然后加载和实例化到容器工厂中。
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {Class<?> contextClass = getContextClass();if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Fatal initialization error in servlet with name '" + getServletName() +"': custom WebApplicationContext class [" + contextClass.getName() +"] is not of type ConfigurableWebApplicationContext");}ConfigurableWebApplicationContext wac =(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);wac.setEnvironment(getEnvironment());wac.setParent(parent);String configLocation = getContextConfigLocation();if (configLocation != null) {wac.setConfigLocation(configLocation);}configureAndRefreshWebApplicationContext(wac);return wac;}
四、DispatchServlet的onfresh加载流程
1.在上述子applicationContext.refresh调用完毕时,会调用publishEvent(new ContextRefreshedEvent(this)),而DispatcherServlet的父类FrameworkServlet有一个内部类实现了applicationListener接口
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {FrameworkServlet.this.onApplicationEvent(event);}}
2.最终会触发到DispatchServlet.onRefresh接口
3.最终会初始化springmvc中的各种策略类。这种会创建对象,注入属性。
protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}
最主要的是初始handlerMapping,即根据URL找到对应的handlerAdapter.
4.初始化handlerAdapter
排序后
5.初始化异常解析器
排序 后
spring mvc 总体启动流程相关推荐
- 接收请求处理流程_从Tomcat入口了解Spring MVC的请求处理流程(2)问题答疑
在上一篇 从Tomcat入口了解Spring MVC的请求处理流程 中主要介绍了spring mvc如何使用以及spring的DispatcherServlet加载细节以及URL映射配置,但是还是遗留 ...
- Spring MVC的处理流程详解
本文来说下Spring MVC 的处理流程是怎样的 文章目录 Spring MVC概述 Spring MVC的处理流程 曾经的王者-Servlet 想要更进一步 Spring MVC-两级控制器方式 ...
- 面试官:Spring MVC的处理流程是怎样的?
提起Spring MVC,你的第一印象是什么?一个简化Web开发的轻量级框架?实际上,现代开发过程中,开发流程与开发效率的不断提高,同时伴随着Restful与Json相结合的方式的兴起,使得多个设备跨 ...
- 请简述Spring MVC的执行流程
需要面试文档可S我 今天我给大家介绍一下Spring MVC的详细执行流程.我把Spring MVC的执行流程划分为三个阶段,配置阶段.初始化阶段和运行阶段. 我整理了一张完整的执行流程图,需要高清图 ...
- Spring MVC中数据绑定流程和原理
Spring MVC不支持表单日期字符串和日期类型之间的转换 Spring MVC数据绑定的流程(Spring MVC通过反射 机制对目标处理方法进行解析) 1.Spring MVC将ServletR ...
- Spring Boot的启动流程
文章目录 Spring Boot Spring Boot概念 Spring Boot的启动流程 1. 构造SpringApplection的实例 2. 调用实例的run方法 Spring Boot启动 ...
- Spring MVC的请求处理流程
Spring MVC的请求处理流程 DispatcherServlet的处理流程图 核心处理流程步骤 DispatcherServlet 的初始化过程 DispatcherServlet的处理流程图 ...
- Spring容器的启动流程
(本文基于 Spring 的 5.1.6.RELEASE 版本) Spring的启动流程可以归纳为三个步骤: 1.初始化Spring容器,注册内置的BeanPostProcessor的BeanDefi ...
- Spring Boot项目启动流程
概述 用过Spring Boot的应该都知道,在项目启动入口的主类main()方法里,一句简简单单的 SpringApplication.run( ... ); 便开启了项目的启动运行之路. 本文我们 ...
最新文章
- Android软键盘遮挡的四种解决方案
- DR模式 mysqlABB读写分离
- Python__面向对象思想
- 笔记-项目风险管理-风险应对
- [MATLAB调试笔记]Field plot (Ex,Ey,Ez,By,Bz)
- RouterOS V2.9.27 固定IP双电信分流教程(详)
- 阿里与网易考拉收购案谈崩?后者股价下跌5.01%
- 软件调试中的断点分类
- UVA 11423 - Cache Simulator (树状数组)
- 高通平台printk输出log到串口
- 线程池工厂方法newFixedThreadPool()和newCachedThreadPool()
- C# 编译器选项 /platform(指定输出平台)32位程序运行到x64平台的问题
- android gradle 在assembleRelease之前 or 之后执行自定义task
- 机械革命bios升级_旧笔记本光驱换SSD,升级内存,改造散热还能再战5年
- 应届生应聘软件开发岗位推荐书籍
- fastai 文本分类_使用Fastai v2和多标签文本分类器检查有毒评论
- VHDL矩阵键盘扫描数码管显示
- 微信小程序 | 小Demo_学生资讯 | 系统性学习 | 无知的我费曼笔记
- 全面的软件测试( 转)
- 深圳软件测试培训:软件测试的需求评审
热门文章
- SAP 取月度期初库存和月度期末库存(历史库存)
- sap中Excel的模版上传和下载
- SAP内存 和 ABAP内存 的简单介绍说明
- 从老赖们“维权”,看拍拍贷的底色
- mysql 5.7巡检脚本_mysql自动化巡检脚本生成html报告
- php中如何比较数组和字符串,PHP中数组和字符串的相互转换-PHP数组和字符串互相转换方法-吾爱编程网...
- mysql 回收空间_MySQL表的碎片整理和空间回收小结
- 启动定时器t0的工作指令是_看门狗的工作原理、应用和设计思路
- SQL语言之DQL语言学习(十一)分页查询
- 键盘和计算机之间的通信是单工通信,通信方式