java Spring的启动原理详解
作者:Java技术债务 发布时间:2022-09-02 04:39:59
引入
为什么突然说一下Spring启动原理呢,因为之前面试的时候,回答的那可谓是坑坑洼洼,前前后后,补补贴贴。。。
总而言之就是不行,再次看一下源码发掘一下。。。
在Spring Boot还没有广泛到家家在用的时候,我们都还在书写繁琐的配置,什么web.xml、spring.xml、bean.xml等等。虽然现在很少,可以说几乎没有企业在去使用Spring的老一套,而会去使用Spring Boot约定大于配置来进行快速开发,但是,Spring的也要去学习,去挖掘,毕竟是我们Java程序员的基础呀。
spring的启动是建筑在servlet容器之上的,所有web工程的初始位置就是web.xml,它配置了servlet的上下文(context)和 * (Listener)
web.xml
<!--上下文 * ,用于监听servlet的启动过程-->
<listener>
<description>ServletContextListener</description>
<!--这里是自定义 * ,个性化定制项目启动提示-->
<listener-class>com.trace.app.framework.listeners.ApplicationListener</listener-class>
</listener>
<!--dispatcherServlet的配置,这个servlet主要用于前端控制,这是springMVC的基础-->
<servlet>
<servlet-name>service_dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/services/service_dispatcher-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!--spring资源上下文定义,在指定地址找到spring的xml配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/application_context.xml</param-value>
</context-param>
<!--spring的上下文 * -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!--Session * ,Session作为公共资源存在上下文资源当中,这里也是自定义 * -->
<listener>
<listener-class>
com.trace.app.framework.listeners.MySessionListener
</listener-class>
</listener>
Spring启动过程
spring的上下文 *
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/application_context.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
spring的启动其实就是IOC容器的启动过程,通过上述的第一段配置 <context-param>
是初始化上下文,然后通过后一段的的<listener>
来加载配置文件,其中调用的spring包中的ContextLoaderListener
这个上下文 * ,ContextLoaderListener
是一个实现了ServletContextListener接口的 * ,他的父类是 ContextLoader,在启动项目时会触发contextInitialized上下文初始化方法。
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
调用了父类ContextLoader的initWebApplicationContext(event.getServletContext());方法,很显然,这是对ApplicationContext的初始化方法,也就是到这里正是进入了springIOC的初始化。
接下来看一下initWebApplicationContext(event.getServletContext())的工作:
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!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
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, etc
if (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.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
总结:
创建WebApplicationContext。加载对应的spring配置文件中的Bean。将WebApplicationContext放入ServletContext(Java Web的全局变量)中。
接下来,来到了configureAndRefreshWebApplicationContext()
方法
作用:
就是用来加载spring配置文件中的Bean实例的。这个方法于封装ApplicationContext数据并且初始化所有相关Bean对象。它会从web.xml
中读取名为 contextConfigLocation的配置,这就是spring xml数据源设置,然后放到ApplicationContext中,最后调用传说中的refresh
方法执行所有Java对象的创建。
总结:
来源:https://blog.csdn.net/qq_40124555/article/details/122732849
猜你喜欢
- 前提: 可以参考文章 SpringBoot 接入 SparkSpringBoot 已经接入 Spark已配置 JavaSparkContex
- 目录Spring自动注入失败如何解决?回答注入你的bean使用@Configurable手动查找bean:不推荐Spring自动注入失败如何
- 本文实例为大家分享了安装和配置maven环境的具体步骤,供大家参考,具体内容如下下载maven:1.进入官网下载:http://maven.
- The java.io.Writer.flush() method flushes the stream. If the stream ha
- 概述最近在对之前写的一个 Spring Boot 的视频网站项目做功能完善,需要利用 FFmpeg 实现读取视频信息和自动截图的功能,查阅资
- 一、递归的思路一个方法在执行时,调用自身被称为“递归”。递归相当于数学归纳法,有一个起始条件,有一个递推公式。递归可以分为:单路递归和多路递
- 第一次写上传图片的代码,碰到很多问题。昨天做了整整一天,终于在晚上的时候成功了。大声欢呼。但是,做完之后,还是有很多问题想不通。所以在这里也
- 今天重新装了编译器,结果崩无极限,真是日了狗了了。刚刚才知道问题在哪边。好了,说正事,对于ios开发我没接触,不是很了解,百度了半天,差不多
- Android版本更新实例详解1、导入xutils的jar包 2、在AndroidManifest.xml中添加权限 3、选择下载的路径,和
- SpringBoot v2.2以上重复读取Request Body内容一、需求项目有两个场景会用到从Request的Body中读取内容。打印
- 本文实例讲述了Java计算文本MD5加密值的方法。分享给大家供大家参考,具体如下:java计算文本MD5值,用于加密import java.
- 简介本文用示例介绍java的Duration的用法。Duration和Period说明Duration类通过秒和纳秒相结合来描述一个时间量,
- java实现接口签名为了保证数据传输的安全性,跟其他系统进行数据交互时,双方应该约定好密钥,把数据进行加密,接口签名,这样双方调用接口时,验
- ★打印九九乘法表public class TestDemo { public static
- 二叉堆是一种特殊的堆,二叉堆是完全二元树(二叉树)或者是近似完全二元树(二叉树)。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于
- Android植物大战僵尸小游戏全部内容如下:相关下载:Android植物大战僵尸小游戏具体代码如下所示:package com.examp
- Vector简介ArrayList 和 Vector 其实大同小异,基本结构都差不多,但是一些细节上有区别:比如线程安全与否,扩容的大小等,
- JAVA中去掉空格 1. String.trim() trim()是去掉首尾空格 2.str
- 前言在一些项目中,经常会遇到需要把当前线程中的上下文传递到其他线程中的情况,比如某项目包含国际化操作,在业务请求进来时需要把对应的国家代码存
- 一、题目描述题目:使用ThreadLocal管理一号和二号线程,分别存入100元,在三号线程中使用利用一号和二号的计算结果来算出账户的实际金