Spring 源码学习(二) IOC容器启动过程

这一节主要是记录一下Spring Ioc 容器的启动过程。

Spring 的 Ioc 容器是怎么被加载和使用的? web容器为它提供了宿主环境 ServlectContext,  Tomcat 启动时会读取web.xml。

并且实例化web.xml中配置的ContextLoaderListener ,下面看一下ContextLoaderListener的创建过程:

在实例化ContextLoaderListener 之后,通过接口回调执行ContextLoaderListener 类中的contextInitialized(ServletContextEvent event)方法,该方法的作用是初始化根上下文

(注:WebApplicationContext 是ApplicationContext 的拓展接口,而Spring默认提供的根上下文是XmlWebApplicationContext。)

代码:

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { 

//若servletContext中存在WebApplicationContext 则抛出异常 

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!");

} 

//…………省略 
//初始化
WebApplicationContext 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) {
//创建webApplication的实例 
this.context =createWebApplicationContext(servletContext); 
}
 //省略代码在下面给出
}

createWebApplicationContext(servletContext) 方法的作用是创建根上下WebApplicationContext的实例

代码:

  protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
        Class<?> contextClass = determineContextClass(sc);
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Custom context class [" + contextClass.getName() +"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
        }
        return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

  }

这里determineContextClass(ServletContext sc)  用于返回ApplicationContext的实现类,如果没有在配置文件中配置自定义的ApplicationContext,默认返回 XmlWebApplicationContext ,得到实例后对其进行检查,满足条件则返回它的实例。

createWebApplicationContext方法下面省略的代码:

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);

这一步是判断返回的根上下文实例context有没有父上下文,取决于在web.xml中定义的参数:locatorFactorySelector,这是一个可选参数,加载完父上下文之后,执行configureAndRefreshWebApplicationContext方法,先看一下源码:

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 information
           //………省略
        }
        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 conte        //xt
        // 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 #refresh
        //………省略
        wac.refresh();
  }

上面的方法setServletContext  为根上下文设置ServletContext的引用 , 执行根上下文的refresh()方法, 就是上一节说的,创建BeanFacotry的过程,执行完这方法在启动日志就可以看到

信息: Loading XML bean definitions from class path resource [spring.xml]

这个时候就完成了对spring.xml资源的读取,到此就结束了根上下文(Application)的配置与加载资源,servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context)这句代码就是把上下文存入ServletContext当中,下次获取根上下文的时候就可以通过 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性获取。

到此ContextLoaderListener的创建就结束了。

Spring 源码学习(二) IOC容器启动过程

时间: 2024-12-26 08:58:35

Spring 源码学习(二) IOC容器启动过程的相关文章

Spring源码阅读:IOC容器的设计与实现(二)——ApplicationContext

上一主题中,了解了IOC容器的基本概念,以及BeanFactory的设计与实现方式,这里就来了解一下ApplicationContext方式的实现. ApplicationContext 在Spring的参考文档中,为啥要推荐使用ApplicationContext?它能给我们的应用带来什么好处呢?作为BeanFactory的实现之一,它又是如何设计的?在SpringMVC中使用的WebApplictionContext\XmlApplicationContext与之有何关联? Applicat

【spring源码分析】IOC容器初始化(总结)

前言:在经过前面十二篇文章的分析,对bean的加载流程大致梳理清楚了.因为内容过多,因此需要进行一个小总结. 经过前面十二篇文章的漫长分析,终于将xml配置文件中的bean,转换成我们实际所需要的真正的bean对象. 总结 [spring源码分析]IOC容器初始化(一):主要分析了Spring是如何解析占位符以及BeanFactory的最终实现类DefaultListableBeanFactory. [spring源码分析]IOC容器初始化(二):以loadBeanDefinitions函数为切

【spring源码分析】IOC容器初始化(十二)

前言:在doCreateBean方法中还遗留一个问题没有分析:循环依赖.循环依赖在Spring中是非常重要的一个知识点,因此单独进行分析. 什么是循环依赖 循环依赖就是循环引用,两个或两个以上的bean互相引用对方,最终形成一个闭环.如A依赖B,B依赖C,C依赖A.如下图所示: 循环依赖其实就是一个死循环的过程,在初始化A的时候发现引用了B,则就会去初始化B,然后发现B又引用C,则又去初始化C,在初始化C的时候,再次发现C引用了A,则又去初始化A,这样就处于死循环,除非有终结条件. Spring

spring源码解析之IOC容器(一)

学习优秀框架的源码,是提升个人技术水平必不可少的一个环节.如果只是停留在知道怎么用,但是不懂其中的来龙去脉,在技术的道路上注定走不长远.最近,学习了一段时间的spring源码,现在整理出来,以便日后温故知新. IOC容器是spring最核心的模块之一,是整个spring体系的基石,spring其他模块中,都需要用到IOC容器的功能.spring框架为我们提供了多种IOC容器,DefaultableBeanFact ory.FileSystemXmlApplicationContext.Class

【spring源码分析】IOC容器初始化(一)

前言:spring主要就是对bean进行管理,因此IOC容器的初始化过程非常重要,搞清楚其原理不管在实际生产或面试过程中都十分的有用.在[spring源码分析]准备工作中已经搭建好spring的环境,并利用xml配置形式对类进行了实例化.在test代码中有一个非常关键的类ClassPathXmlApplicationContext,在这个类中实现了IOC容器的初始化,因此我们从ClassPathXmlApplicationContext入手开始研究IOC的初始化过程. 1.ClassPathXm

[spring源码学习]二、IOC源码——配置文件读取

一.环境准备 对于学习源码来讲,拿到一大堆的代码,脑袋里肯定是嗡嗡的,所以从代码实例进行跟踪调试未尝不是一种好的办法,此处,我们准备了一个小例子: package com.zjl; public class Person { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void sayHello

spring源码解析之IOC容器(二)------加载和注册

上一篇跟踪了IOC容器对配置文件的定位,现在我们继续跟踪代码,看看IOC容器是怎么加载和注册配置文件中的信息的.开始之前,首先我们先来了解一下IOC容器所使用的数据结构-------BeanDefinition,它是一个上层接口,有很多实现类,分别对应不同的数据载体.我们平时开发的时候,也会定义很多pojo类,来作为获取数据的载体.最常见的就是,从数据库中获取数据之后,使用一个定义的pojo来装载,然后我们就可以在程序中使用这个pojo类来编写各种业务逻辑.同样,IOC容器首先会读取配置的XML

Spring源码分析之IOC容器(一)

Spring作为当今风靡世界的Web领域的第一框架,作为一名Java开发程序员是一定要掌握的,除了需要掌握基本的使用之外,更需要掌握其实现原理,因为我们往往在开发的过程中,会出现各种各样的异常问题.而且这样的问题去百度有时候往往也找不到特别有效的解决方法,因为问题的原因非常多而百度的又不准确,这个时候怎么办呢?在熟练掌握Spring代码的情况下,我们可以根据提示的异常信息,去跟到源代码的地方,可以准确的定位到异常的所在,这就犹如debug调试自己的业务逻辑一样轻松了,所以Spring的源代码非常

spring源码研究之IoC容器在web容器中初始化过程

前段时间在公司做了一个项目,项目用了spring框架实现,WEB容器是Tomct 5,虽然说把项目做完了,但是一直对spring的IoC容器在web容器如何启动和起作用的并不清楚.所以就抽时间看一下spring的源代码,借此了解它的原理. 我们知道,对于使用Spring的web应用,无须手动创建Spring容器,而是通过配置文件,声明式的创建Spring容器.因此在Web应用中创建Spring容器有如下两种方式: 1. 直接在web.xml文件中配置创建Spring容器. 2. 利用第三方MVC

spring源码解析之IOC容器(三)——依赖注入

上一篇主要是跟踪了IOC容器对bean标签进行解析之后存入Map中的过程,这些bean只是以BeanDefinition为载体单纯的存储起来了,并没有转换成一个个的对象,今天继续进行跟踪,看一看IOC容器是怎样实例化对象的. 我们都使用过以下代码: 1 FileSystemXmlApplicationContext context=new FileSystemXmlApplicationContext("bean.xml"); 2 User user=context.getBean(&