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


猜你喜欢
- GlobalLock的作用对于某条数据进行更新操作,如果全局事务正在进行,当某个本地事务需要更新该数据时,需要使用@GlobalLock确保
- 这次记录的是实现Android图片两手触控缩放的功能。编译环境:eclipseAndroid版本4.0创建工程过程略实现图片在页面两手触控缩
- Spring使用AOP完成统一结果封装起因:自己写项目的时候忍受不了每个方法都要写一个retrun Result.success();和 r
- C语言数据结构之二叉树的非递归后序遍历算法前言:前序、中序、后序的非递归遍历中,要数后序最为麻烦,如果只在栈中保留指向结点的指针,那是不够的
- 最近安装了idea,觉得比eclipse好用很多,今天不知道为啥yml文件就不识别了,上面显示一个问号,我查了半天,解决办法就是安装一个插件
- Maven可以使用mvn package指令对项目进行打包,如果使用java -jar xxx.jar执行运行jar文件,会出现"
- 要讲到C#源码的执行过程 首先要提下程序集,因为Clr并不是和托管摸块打交道的,而是和程序集(dll,exe)1、从哪里来程序集是由一个或者
- 如下所示:@Overridepublic void onWindowFocusChanged(boolean hasFocus) {supe
- 前言本文主要给大家介绍了关于C#连接FTP时路径问题的相关内容,分享出来供大家参考学习,话不多说,来一起看看详细的介绍:今天在开发项目时,需
- 序言springboot框架价值,可以简单快速的构建独立的spring生产级别应用。springboot主要有以下的特性:1.创建独立的Sp
- 前言如果你了解过 Liunx ,了解过 Liunx 的中管道命令 | ,那么你会发现,其实 Java 8 的 stream 和 Liunx
- 一.继承的类型在面向对象的编程中,有两种截然不同继承类型:实现继承和接口继承1.实现继承和接口继承*实现继承:表示一个类型派生于基类型,它拥
- mybatis-plus自动配置mapper.xml与java接口映射本来没有mybatis-plus的话,这个工作是通过mybatis-s
- 1.Spring中的 * 在web开发中, * 是经常用到的功能。它可以帮我们预先设置数据以及统计方法的执行效率等等。今天就来详细的谈一下s
- 本文实例讲述了C#实现对数组进行随机排序类。分享给大家供大家参考。具体如下:这个一个扩充C#随机数发生器的类,可以随机生成指定范围的数字,可
- 1.会话会话: 用户打开了一个浏览器,点击了很多超链接,访问多个web次元,关闭浏览器,这个过程可以称之为会话有状态会话: 带有访问记录的会
- java 请求跨域问题解决方法实例详解新建Util类,在Util中添加下面方法: /* * response请求跨域公共设置
- 本文涉及3个基本点:1、因为很多公司的内网都设有代理,浏览器通过ip与port上网,而java代码模拟http get方式同样需要外网代理;
- 本文实例讲述了C#索引属性的用法。分享给大家供大家参考。具体如下:这里演示C#类如何声明索引属性以表示不同种类事物的类似数组的集合。// i
- 本文实例为大家分享了Android自定义View实现波浪动画的具体代码,供大家参考,具体内容如下效果演示代码调用与实现效果xml中调用<