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对象的创建。

总结:

java Spring的启动原理详解

来源:https://blog.csdn.net/qq_40124555/article/details/122732849

标签:spring,java,启动原理
0
投稿

猜你喜欢

  • Java利用反射对list对象做过滤

    2023-12-23 07:39:17
  • java面试题——详解HashMap和Hashtable 的区别

    2023-08-06 16:38:25
  • Java时间工具类Date的常用处理方法

    2022-11-08 02:37:49
  • Springboot2.0处理自定义异常并返回json

    2021-06-01 03:42:24
  • springboot+gradle 构建多模块项目的步骤

    2023-02-19 00:33:31
  • Java常用类String的面试题汇总(java面试题)

    2023-11-23 20:40:45
  • 基于Java ActiveMQ的实例讲解

    2023-08-24 08:39:38
  • Mybatis-Spring源码分析图解

    2023-07-18 13:35:07
  • Java OkHttp框架源码深入解析

    2023-11-29 03:22:50
  • 如何自动生成Mybatis的Mapper文件详解

    2023-07-28 08:20:54
  • 教你使用idea搭建ssm详细教程(Spring+Spring Mvc+Mybatis)

    2021-09-23 12:37:42
  • java实现sftp客户端上传文件以及文件夹的功能代码

    2023-02-14 22:07:28
  • 三步轻松搭建springMVC框架

    2023-02-01 05:38:34
  • 一文看懂JAVA设计模式之工厂模式

    2023-11-27 02:30:54
  • Java实现简单员工管理系统

    2021-12-13 17:51:26
  • Java 如何实现一个http服务器

    2022-03-27 05:40:04
  • Java设计模式之动态代理模式实例分析

    2022-07-07 17:55:07
  • SpringBoot整合Security安全框架实现控制权限

    2022-10-03 14:37:15
  • Java Socket通信之聊天室功能

    2022-02-04 11:47:35
  • 深入解析Java中的Classloader的运行机制

    2023-07-16 11:47:59
  • asp之家 软件编程 m.aspxhome.com