1 环境说明

本文的内容基于Tomcat9.0.10、Spring 4.3

2 Tomcat加载应用的顺序

在我们正式介绍SSM项目是怎么启动之前,我们要先来简单介绍一下Tomcat。很多人在介绍Tomcat的时候,都把Tomcat叫做Servlet容器,之所以这样称呼Tomcat,是因为Tomcat就是一个围绕着Servlet工作的一个服务器软件,最直观、也最简单粗暴的解释就是在Tomcat上运行的应用,都是基于servlet-api.jar这个jar包来开发的。打开tomcat安装目录下的conf文件夹中的server.xml,我们可以看到它的主要节点如下:

<Server><Service><Connector/><Connector/><Engine><Host><!--  现在常常使用自动部署,所以在配置文件中找不到Context元素,可以手动添加 --><Context/></Host></Engine></Service>
...
</Server>

其中,Engine、Host、Context都是继承于一个叫做Container的类,此外还有一个比较特殊的类:Wrapper,这个类是跟项目中我们写的每一个Servlet类(在SpringMVC中对应着Controller类中的一个方法)是一一对应的,在其具体实现类中,就是使用了一个Stack类来存储所有其对应着的Servlet类的实例。大家记住这个结论就行,如果你真的想了解其中的具体细节,就需要去看一下Tomcat的源码了,我后面如果有时间的话,可能也会出一个看Tomcat源码的系列博客。为了方便大家理解,我画了一个图来帮助大家理解。每个不同的部件我都用不同的颜色标了出来,通过下面的图可以很清楚的看到,一个Tomcat就是最外面棕色的框,然后一个Tomcat可以有多个Service组件,一个Service可以有多个Connector组件和一个Engine组件,值得注意的是,不同的Connector的端口号都必须是唯一的,不能跟其他的端口重复,这个只要是学过计算机网络的应该知道这个规则。而每个Engine组件对应着多个Host组件,每个Host组件又对应着多个Context组件,每个Context组件下面对应的则是Wrapper(一般情况下,大家理解为Servlet也是没有问题的)。这里说一下Host(虚拟主机)的作用:运行多个Web应用(一个代表一个Web应用),并负责安装、展开、启动和结束每个Web应用。其中,Context组件对应着的则是我们所开发的应用。

Tomcat的各个组件 Tomcat在启动时通过它自定义的类加载器去各个Host(虚拟主机)指定的路径下加载相关的Web应用,然后将Web应用部署其到对应的Host虚拟主机中,如果Host主机设置了自动部署,Tomcat 在运行时会定期检查是否有新的Web应用或Web应用是否进行了更新。

Tomca自定义的类加载器会按照如下的顺序扫描并加载相关应用和检查应用是否有更新:

  1. 扫描虚拟主机指定的xmlBase下的XML配置文件
  2. 扫描虚拟主机指定的appBase下的WAR文件
  3. 扫描虚拟主机指定的appBase下的应用目录

3 SSM的启动流程

当Tomcat把加载了应用之后,会先读取项目中的web.xml的内容,读取顺序是从上到下一行一行的读的,但是加载顺序是先加载context-param元素中的值,然后加载listener元素中的值,接着是加载filter元素中的值,最后才是servlet元素中的值。这里给一下我的web.xml对应的内容

<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"version="4.0"><!--定义web应用的名称--><display-name>ssmdemo</display-name><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring/spring-context.xml</param-value></context-param><!-- Spring上下文监听器,用来加载Spring的上下文配置并初始化Spring --><listener><description>启动spring容器</description><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!-- LOG4J上下文监听器,用来加载LOG4J2的配置并初始化LOG4J --><listener><listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class></listener><listener><listener-class>com.yixiaojun.ssmdemo.listener.MySessionListener</listener-class></listener><!-- 字符编码过滤器,将编码改为UTF-8--><filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><!--对所有的请求都进行过滤--><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><!-- SpringMVC前置控制器,拦截匹配的请求,把拦截下来的请求,根据相应的规则分发到目标Controller来处理--><servlet><servlet-name>spring-mvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定路径SpringMVC上下文配置路径,也可以使用默认的规则,即:/WEB-INF/<servlet-name>-servlet.xml,如spring-mvc-servlet.xml--><init-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/spring/spring-mvc.xml</param-value></init-param><!-- 随web应用启动而启动 --><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>spring-mvc</servlet-name><!--指定所有请求都通过DispatcherServlet来处理--><url-pattern>/</url-pattern></servlet-mapping></web-app>

所以我们就可以得出SSM的加载流程了,具体流程如下图:

我们也可以通过观看日志的输出顺序来查看项目的启动流程是怎么样的,下面是我从一个SSM项目的启动过程中抽取的一部分关键日志,说明就以注释形式写在里面了。

#Tomcat启动成功后,开始连接到Tomcat
Connected to server#发现项目的war包,开始部署项目
Artifact ssmdemo:war exploded: Artifact is being deployed, please wait...#加载监听器中配置的org.springframework.web.context.ContextLoaderListener的父类ContextLoader中的initWebApplicationContext 方法,初始化应用上下文
org.springframework.web.context.ContextLoader.initWebApplicationContext Root WebApplicationContext: initialization started#初始化SpringIOC容器
org.springframework.web.context.support.XmlWebApplicationContext.prepareRefresh Refreshing Root WebApplicationContext#加载从context-param中配置的contextConfigLocation的值所对应的文件spring-context.xml
org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/spring-context.xml]#加载spring-context.xml中配置的/mybatis-config.xml
org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:496) - Parsed configuration file: 'ServletContext resource [/WEB-INF/mybatis/mybatis-config.xml]'#加载spring-context.xml指定的mapper目录下的xml文件
org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:528) - Parsed mapper file: 'file [D:\Project\ssmdemo\target\ssmdemo\WEB-INF\classes\mapper\UserMapper.xml]'# 应用初始化完成
org.springframework.web.context.ContextLoader.initWebApplicationContext Root WebApplicationContext: initialization completed in 1605 ms#开始开始加载Servlet配置的内容,即调用org.springframework.web.servlet.DispatcherServlet的父类FrameworkServlet 的initServletBean
org.springframework.web.servlet.DispatcherServlet.initServletBean FrameworkServlet 'spring-mvc': initialization started#初始化SpringMVC的IOC容器
org.springframework.web.context.support.XmlWebApplicationContext.prepareRefresh Refreshing WebApplicationContext for namespace 'spring-mvc-servlet': startup date [Wed May 27 00:25:46 CST 2020]; parent: Root WebApplicationContext#通过servlet容器配置的contextConfigLocation所对应的的文件来生成SpirngMVC的BeanDefinitions
org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions Loading XML bean definitions from ServletContext resource [/WEB-INF/spring/spring-mvc.xml]#生成静态资源的映射url路径
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping.registerHandler Mapped URL path [/js/**] onto handler 'org.springframework.web.servlet.resource.ResourceHttpRequestHandler#0'#生成Controller类的中的方法的映射url路径
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.register Mapped "{[/user/login],methods=[GET]}" onto public void com.yixiaojun.ssmdemo.controller.UserController.login(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) throws java.io.IOException#初始化AOP要拦截的切点
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.initControllerAdviceCache Looking for @ControllerAdvice: WebApplicationContext for namespace 'spring-mvc-servlet': startup date [Wed May 27 00:25:46 CST 2020]; parent: Root WebApplicationContext#SpirngMVC初始化完成
org.springframework.web.servlet.DispatcherServlet.initServletBean FrameworkServlet 'spring-mvc': initialization completed in 1584 ms

4 部分Spring相关源码

4.1ContextLoaderListener.java

package org.springframework.web.context;
public class ContextLoaderListener extends ContextLoader
implements ServletContextListener  {public void contextInitialized(ServletContextEvent event)  {this.initWebApplicationContext(event.getServletContext());}}

4.2 ContextLoader.java

package org.springframework.web.context;public class ContextLoader {public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {this.context  =  this.createWebApplicationContext(servletContext);this.configureAndRefreshWebApplicationContext(cwac, servletContext);//将初始化之后的上下文存到servletContext中servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);return this.context;}protected  void configureAndRefreshWebApplicationContext( ConfigurableWebApplicationContext wac,ServletContext sc) {wac.setServletContext(sc);//从ServletContext获取contextConfigLocation的值configLocationParam  =  sc.getInitParameter("contextConfigLocation");if(configLocationParam != null) {wac.setConfigLocation(configLocationParam);}//刷新XmlWebApplicationContext(初始化SpringIOC容器)wac.refresh();}
}

4.3 AbstractApplicationContext.java

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean {public void refresh() throws BeansException, IllegalStateException {Object var1 = this.startupShutdownMonitor;synchronized(this.startupShutdownMonitor){//刷新前准备工作,记录容器启动时间和标记this.prepareRefresh();//创建bean工厂,读取XML配置里的Bean信息,装载XML配置里面的BeanDefinitionConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//准备Bean工厂需要的上下文信息,包括对 @Autowired和@Qualifier注解的属性注入this.prepareBeanFactory(beanFactory); try {this.postProcessBeanFactory(beanFactory);//激活各种  BeanFactory  处理器this.invokeBeanFactoryPostProcessors(beanFactory);//注册各种BeanPostProcessors,用于在bean被初始化时进行拦截,进行额外初始化操作,具体可以查看Bean的生命周期this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();// 初始化所有未初始化的非懒加载的单例Beanthis.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();}catch(BeansException  var9){}this.destroyBeans();this.cancelRefresh(var9); throw  var9;} finally  {this.resetCommonCaches();}}
}

SSM项目的启动流程深入解析相关推荐

  1. Vue脚手架创建的项目的启动流程

    Vue脚手架创建的项目的启动流程 当利用vue脚手架创建项目之后利用 npm run serve 启动开发环境,我们就从这里来开始分析. 入口分析 首先从package.json中的脚本配置来看,np ...

  2. busybox启动流程简单解析:从init到shell login

    https://www.cnblogs.com/arnoldlu/p/10868354.html busybox启动流程简单解析:从init到shell login 关键词:kernel_init() ...

  3. idea 配置ssm项目后配置文件的简要解析及功能类之间的联系

    注:本文不包含怎么配置 idea ssm 项目,仅做个人向配置好之后,对于各个文件的分析及跳转之间的的浅解析(之前照着配的文章找不到了qwq). 叠甲:新手,刚学,不太会,如有错请指出,谢谢! 目录 ...

  4. Vue笔记:webpack项目vue启动流程

    VUE启动流程 1. package.json 在执行npm run dev的时候,会在当前目录中寻找 package.json 文件, 有点类似 Maven 的 pom.xml 文件,包含项目的名称 ...

  5. SSM项目tomcat启动失败-Multiple Contexts have a path of “/ssm-crud“

    错误: 1.Server中ssm-crud的路径重复 2.C:\Users\XUCHE\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.ser ...

  6. App 启动流程全解析

    概述 Activity 启动过程分为两种,一种是根Activity的启动过程,另一种是普通Activity的启动过程.这里介绍是是根Activity的启动过程,也可以理解为应用程序启动过程. Laun ...

  7. SSM项目tomcat启动不了,spring配置问题。Caused by: java.lang.IllegalStateException: Cannot convert value of type

    原因是spring配置文件出错了. 在配置springxml文件时,注意数据库引入不能用value,还有一些对象的引用不能用value. 改成ref就ok了.虽然这个问题很简单,但又有可能被忽略. 再 ...

  8. 跟我一起学.NetCore之Asp.NetCore启动流程浅析

    前言 一个Asp.NetCore项目,知道大概的启动流程是有必要的,比如后续遇见配置信息覆盖等相关问题时也大概知道是什么原因,了解原因之后,再去搜索引擎找答案,否则目标不明确,茫茫人海怎么会一下找到自 ...

  9. I.MX6 Linux Qt 启动流程跟踪

    /*************************************************************************** I.MX6 Linux Qt 启动流程跟踪* ...

最新文章

  1. InfoPath 揭秘 (一)
  2. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY3-线性模型
  3. haproxy小结(一)基础概念篇
  4. unity_小功能实现(敌人巡逻功能)
  5. 红歌合唱之团结就是力量
  6. 前端为什么非要动静分离 说一下CDN托管的意义
  7. Nemo(Nightwish乐队)
  8. JavaScript 之 面向对象 [ 原型 ]
  9. Python+Selenium+Edge浏览器安装与简单运行(1/2)
  10. KTHREAD 线程调度 SDT TEB SEH shellcode中DLL模块机制动态获取 《寒江独钓》内核学习笔记(5)...
  11. 第二十三期:你用的Windows操作系统是不是盗版?微软知道吗
  12. Java项目:员工出差请假考勤管理系统(java+JSP+LayUI+HTML+servlet+Mysql)
  13. Visio绘制ER图-
  14. 硅谷大佬们屡次推荐的10本书,你看过几本?
  15. 【项目实战】Python基于Apriori关联规则算法实现商品零售购物篮分析
  16. oracle 无效的窗口句柄 print spooler服务已开,win10系统下无法运行print spooler服务如何解决...
  17. 手把手教你开发列举网自动发帖软件!神器哈
  18. SAP云平台里的三叉戟应用
  19. 【综合类型第 35 篇】程序员的七夕浪漫时刻
  20. OpenCV中的利用傅里叶梅林变换进行平移旋转图像的比对

热门文章

  1. 安全生产危化品经营单位安全管理人员一[安考星]
  2. 数据库期中考试这一篇就够了
  3. C语言数组——二维数组
  4. Python Kmeans K均值分类
  5. Qt实现的酷炫轮播图
  6. 汇编语言学习——mov指令(转载)
  7. Android 与 H5 交互基础普及
  8. 简历不要随意给猎头!他们会胡乱投递,影响你之后求职!
  9. 电脑怎么恢复手机拍的照片文件
  10. XML语言数据读写理解3