`

spring ioc容器初始化(转载)

 
阅读更多
Spring MVC中的IoC容器初始化 

2012-03-02 09:29:20|  分类: springMVC |字号 订阅
Spring Framework本身没有Web功能,Spring MVC使用WebApplicationContext类扩展ApplicationContext,使得拥有web功能。那么,Spring MVC是如何在web环境中创建IoC容器呢?web环境中的IoC容器的结构又是什么结构呢?web环境中,spring IoC容器是怎么启动呢?

      先看一下WebApplicationContext是如何扩展ApplicationContext来添加对Web环境的支持的。WebApplicationContext接口定义如下:
[java] view plaincopy

    public interface WebApplicationContext extends ApplicationContext { 
        //根上下文在ServletContext中的名称 
            String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT"; 
            //取得web容器的ServletContext 
        ServletContext getServletContext(); 
    } 

      对于web容器中创建IoC容器的过程,我们从web.xml配置文件讲起。看一下Spring MVC的web.xml中的相关配置:
[xhtml] view plaincopy

    <context-param> 
            <param-name>contextConfigLocation</param-name> 
            <param-value>/WEB-INF/applicationContext.xml</param-value> 
        </context-param> 
         
        <listener> 
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
        </listener> 
     
        <!-- Handles all requests into the application --> 
        <servlet> 
            <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> 
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
            <init-param> 
                <param-name>contextConfigLocation</param-name> 
                <param-value> 
                    /WEB-INF/spring/*.xml 
                </param-value> 
            </init-param> 
            <load-on-startup>1</load-on-startup> 
        </servlet> 
             
        <!-- Maps all /app requests to the DispatcherServlet for handling --> 
        <servlet-mapping> 
            <servlet-name>Spring MVC Dispatcher Servlet</servlet-name> 
            <url-pattern>/app/*</url-pattern> 
        </servlet-mapping> 

      在web.xml配置文件中,有两个主要的配置:ContextLoaderListener和DispatcherServlet。同样的关于 spring配置文件的相关配置也有两部分:context-param和DispatcherServlet中的init-param。那么,这两部分 的配置有什么区别呢?它们都担任什么样的职责呢?

      在Spring MVC中,Spring Context是以父子的继承结构存在的。Web环境中存在一个ROOT Context,这个Context是整个应用的根上下文,是其他context的双亲Context。同时Spring MVC也对应的持有一个独立的Context,它是ROOT Context的子上下文。

      对于这样的Context结构在Spring MVC中是如何实现的呢?下面就先从ROOT Context入手,ROOT Context是在ContextLoaderListener中配置的,ContextLoaderListener读取context-param中 的contextConfigLocation指定的配置文件,创建ROOT Context。下面看一下ContextLoaderListener中创建context的源码:
[java] view plaincopy

    /**
         * Initialize Spring's web application context for the given servlet context,
         * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
         * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
         * @param servletContext current servlet context
         * @return the new WebApplicationContext
         * @see #CONTEXT_CLASS_PARAM
         * @see #CONFIG_LOCATION_PARAM
         */ 
        public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { 
                    //PS : ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE=WebApplicationContext.class.getName() + ".ROOT" 根上下文的名称 
                      //PS : 默认情况下,配置文件的位置和名称是: DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml" 
                      //在整个web应用中,只能有一个根上下文 
            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 { 
                // Determine parent for root web application context, if any. 
                ApplicationContext parent = loadParentContext(servletContext); 
     
                // Store context in local instance variable, to guarantee that 
                // it is available on ServletContext shutdown. 
                            // 在这里执行了创建WebApplicationContext的操作 
                this.context = createWebApplicationContext(servletContext, parent); 
     
                            //PS: 将根上下文放置在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对象是如何创建的:
[java] view plaincopy

    protected WebApplicationContext createWebApplicationContext(ServletContext sc, ApplicationContext parent) { 
                    //根据web.xml中的配置决定使用何种WebApplicationContext。默认情况下使用XmlWebApplicationContext 
                    //web.xml中相关的配置context-param的名称“contextClass” 
            Class<?> contextClass = determineContextClass(sc); 
            if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { 
                throw new ApplicationContextException("Custom context class [" + contextClass.getName() + 
                        "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); 
            } 
     
                    //实例化WebApplicationContext的实现类 
            ConfigurableWebApplicationContext wac = 
                    (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); 
     
            // Assign the best possible id value. 
            if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) { 
                // Servlet <= 2.4: resort to name specified in web.xml, if any. 
                String servletContextName = sc.getServletContextName(); 
                if (servletContextName != null) { 
                    wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + servletContextName); 
                } 
                else { 
                    wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX); 
                } 
            } 
            else { 
                // Servlet 2.5's getContextPath available! 
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + sc.getContextPath()); 
            } 
     
            wac.setParent(parent); 
     
            wac.setServletContext(sc); 
                    //设置spring的配置文件 
            wac.setConfigLocation(sc.getInitParameter(CONFIG_LOCATION_PARAM)); 
            customizeContext(sc, wac); 
                    //spring容器初始化 
            wac.refresh(); 
            return wac; 
        } 



       以上是web容器中根上下文的加载与初始化,下面介绍一下Spring MVC对应的上下文是如何加载的。

    

       Spring MVC中核心的类是DispatcherServlet,在这个类中完成Spring context的加载与创建,并且能够根据Spring Context的内容将请求分发给各个Controller类。DispatcherServlet继承自HttpServlet,关于Spring Context的配置文件加载和创建是在init()方法中进行的,主要的调用顺序是 init-->initServletBean-->initWebApplicationContext。

       先来看一下initWebApplicationContext的实现
[java] view plaincopy

    /**
         * Initialize and publish the WebApplicationContext for this servlet.
         * <p>Delegates to {@link #createWebApplicationContext} for actual creation
         * of the context. Can be overridden in subclasses.
         * @return the WebApplicationContext instance
         * @see #setContextClass
         * @see #setContextConfigLocation
         */ 
        protected WebApplicationContext initWebApplicationContext() { 
                    //先从web容器的ServletContext中查找WebApplicationContext 
            WebApplicationContext wac = findWebApplicationContext(); 
            if (wac == null) { 
                // No fixed context defined for this servlet - create a local one. 
                            //从ServletContext中取得根上下文 
                WebApplicationContext parent = 
                        WebApplicationContextUtils.getWebApplicationContext(getServletContext()); 
                            //创建Spring MVC的上下文,并将根上下文作为起双亲上下文 
                wac = createWebApplicationContext(parent); 
            } 
     
            if (!this.refreshEventReceived) { 
                // Apparently not a ConfigurableApplicationContext with refresh support: 
                // triggering initial onRefresh manually here. 
                onRefresh(wac); 
            } 
     
            if (this.publishContext) { 
                // Publish the context as a servlet context attribute. 
                            // 取得context在ServletContext中的名称 
                String attrName = getServletContextAttributeName(); 
                            //将Spring MVC的Context放置到ServletContext中 
                getServletContext().setAttribute(attrName, wac); 
                if (this.logger.isDebugEnabled()) { 
                    this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() + 
                            "' as ServletContext attribute with name [" + attrName + "]"); 
                } 
            } 
     
            return wac; 
        } 

        通过initWebApplicationContext方法的调用,创建了DispatcherServlet对应的context,并将其放置到ServletContext中,这样就完成了在web容器中构建Spring IoC容器的过程。



        最后,在分别给出ContextLoaderListener和DispatcherServlet构建context的时序。



        ContextLoaderListener构建Root Context时序图:

ContextLoaderListener

         DispatcherServlet创建context时序图:

DispatcherServlet创建context时序图

(转载:http://xuzhaoshancm.blog.163.com/blog/static/5111889120122292920389/)
  • 大小: 71.5 KB
  • 大小: 75.2 KB
分享到:
评论

相关推荐

    Spring的IoC容器初始化源码解析

    ### Spring的IoC容器初始化源码解析 #### 一、Spring框架的核心——IoC容器 Spring框架是一个开源的轻量级Java开发框架,其核心功能是IoC(Inversion of Control,控制反转)容器和AOP(Aspect Oriented ...

    Spring IOC容器实现分析.pdf 下载

    《Spring IOC容器实现分析》 在Java开发领域,Spring框架无疑是使用最为广泛的轻量级框架之一,其中的核心组件就是IOC(Inversion of Control)容器。本文将深入剖析Spring的IOC容器,理解其工作原理和重要功能,以...

    手写一个SpringIoc容器

    本项目"手写一个SpringIoc容器"旨在模仿Spring的IOC(Inversion of Control,控制反转)功能,帮助开发者深入理解Spring的工作原理,提升对依赖注入(Dependency Injection)模式的认识。 在实现自定义的Spring IOC...

    spring ioc和aop原理流程图(详细)

    2. **容器初始化**:当Spring容器启动时,会读取配置信息并构建Bean的定义。这个过程包括解析配置文件、实例化Bean定义、处理依赖注入等。 3. **依赖注入(DI)**:是IOC的核心。Spring容器负责管理Bean的生命周期...

    springIoc实现原理

    4. **初始化**:Spring容器调用Bean的初始化方法,完成对象的初始化。 5. **Bean管理**:Spring容器负责Bean的生命周期管理,包括销毁等操作。 **六、应用场景** Spring Ioc广泛应用于各种项目中,如: - 数据...

    Java-Spring-SpringIoC容器-SpringIoC的学习

    在Java Spring框架中,Spring IoC(Inversion of Control,控制反转)是核心特性之一,它使得应用程序的组件之间的依赖关系不再由代码直接管理,而是交由Spring IoC容器负责。这种设计模式降低了代码间的耦合,提高...

    详解Spring IOC 容器启动流程分析

    initMessageSource() 方法会初始化消息源,而 initApplicationEventMulticaster() 方法会初始化事件多播器。 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext 是两种常用的 ...

    Spring IOC容器应用实例

    在 Spring 中,IoC 容器负责初始化、配置和管理对象,以及它们之间的依赖关系。 首先,我们来理解什么是依赖注入。在传统的编程中,一个类通常会直接创建它需要的对象,这种方式导致了硬编码的依赖关系。而依赖注入...

    spring IOC容器依赖注入XML配置

    在本教程中,我们将深入探讨如何通过XML配置在Spring IOC容器中实现依赖注入。 首先,我们需要了解Spring的IOC容器。IOC容器是Spring的核心,它负责管理对象的生命周期和对象间的依赖关系。容器通过读取XML配置文件...

    Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程.doc

    Spring 框架系列(7)- Spring IOC 实现原理详解之 IOC 初始化流程 本文将详细解释 Spring 框架中的 IOC...IOC 容器的初始化流程是 Spring 框架中的关键部分,用于将资源配置文件中的信息加载到 IOC 容器中。

    简单模拟springIoc容器

    4. **bean的生命周期管理**:IoC容器还负责对象的初始化、销毁等生命周期管理。这可以通过在XML配置中指定初始化方法和销毁方法,或者使用`@PostConstruct`和`@PreDestroy`注解。 在实际开发中,Spring提供了更高级...

    模拟Spring的IoC容器实现注解自动装配

    IoC容器是通过扫描应用程序上下文来发现所有需要管理的bean,并根据bean定义来创建和初始化这些bean。在Spring中,bean可以通过XML配置、Java配置或者注解进行定义。在模拟实现时,我们可以创建一个`BeanDefinition`...

    仿spring ioc 容器

    4. **生命周期管理**:Spring允许对Bean的初始化和销毁进行定制,仿制品也需要提供类似的机制,如初始化方法调用和销毁方法调用。 5. **AOP支持**:虽然这不是IoC容器的基本功能,但Spring的另一个亮点是面向切面...

    Spring IOC容器实现分析

    ### Spring IOC容器实现分析 #### 一、Spring IOC容器概览 Spring框架作为一款轻量级的开源框架,其核心之一便是IOC(Inversion of Control)容器。该容器的主要功能在于管理和控制对象间的依赖关系,使得开发人员...

    Spring IoC源码深度剖析开源架构源码2021.pdf

    文档可能将深入探讨Spring IoC容器初始化、Bean生命周期管理、依赖注入等关键概念,并以2021年的开源版本为背景进行分析。 从提供的部分文档内容来看,我们可以提炼出以下几个知识点: 1. **BeanFactory与...

    Spring实现一个简单的SpringIOC容器

    本文将深入探讨如何实现一个简单的Spring IOC容器,以及涉及的主要知识点。 首先,控制反转是一种设计模式,它将对象的创建和管理从对象本身转移到一个外部容器,即IOC容器。Spring的IOC容器通过读取配置文件(如...

    springioc的详细讲解

    在Spring框架中,IOC容器是整个应用的中心,它负责初始化、配置和管理所有Bean的生命周期。以下是对Spring IOC容器的详细讲解: 1. **Bean的定义**:在Spring中,我们通过XML、Java配置或者基于注解的方式定义Bean...

    SpringIoc示例代码

    而在Spring IOC中,这种控制权被反转,对象的创建、初始化、依赖关系的装配等都交给了Spring容器来管理。这一设计模式使得应用程序的组件解耦,提高了代码的可测试性和可维护性。 首先,让我们了解一下Spring IOC的...

Global site tag (gtag.js) - Google Analytics