zoukankan      html  css  js  c++  java
  • spring启动入口

    spring启动入口

    (44条消息) spring启动入口_lieyanhaipo的专栏-CSDN博客_spring 入口类

    一、Spring与WEB容器整合   

    web项目中,Spring启动是在web.xml配置监听器,如下所示: 

    Xml代码   收藏代码
    1. <!-- 配置Spring上下文监听器 -->  
    2. <listener>  
    3.     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    4. </listener>  

     
      可以看看ContextLoaderListener类,它实现了Tomcat容器的ServletContextListener接口,所以它与普通的Servlet监听是一样的。同样是重写到两个方法:contextInitialized()方法在web容器初始化时执行,contextDestroyed()方法在容器销毁时执行。

        WEB容器启动时会触发初始化事件,ContextLoaderListener监听到这个事件,其contextInitialized()方法会被调用,在这个方法中Spring会初始化一个根上下文,即WebApplicationContext。这是一个接口,其实际默认实现类是XmlWebApplicationContext。这个就是Spring IOC的容器,其对应bean定义的配置信息由web.xml中的context-param来指定

    Xml代码   收藏代码
    1. <!-- 配置Spring配置文件路径 -->  
    2. <context-param>  
    3.     <param-name>contextConfigLocation</param-name>  
    4.     <param-value>classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml  
    5.         </param-value>  
    6. </context-param>  

     在Spring IOC 容器启动初始化完毕之后,会将其储存到ServletContext中。形式如下:servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, WebApplicationContext context);



     
    注:以前我们写Servlet程序的时候,如果在Tomcat容器启动的时候需要绑定一些参数或者做一些全局处理,那么就需要实现ServletContextListener接口,在contextInitialized方法中编写必要的代码。然后在web.xml添加配置listener

     在ContextLoaderListener类中,只是实现了ServletContextListener提供的到两个方法,Spring启动主要的逻辑在父类ContextLoader的方法initWebApplicationContext实现。ContextLoaderListener的作用就是启动web容器时自动装配ApplicationContext的配置信息。更细化一点讲,Spring的启动过程其实就是Spring IOC容器的启动过程。

    Java代码   收藏代码
    1. public class ContextLoaderListener extends ContextLoader implements ServletContextListener {  
    2.   
    3.     /** 
    4.      * Initialize the root web application context. 
    5.      */  
    6.     @Override  
    7.     public void contextInitialized(ServletContextEvent event) {  
    8.         initWebApplicationContext(event.getServletContext());  
    9.     }  
    10.   
    11.     /** 
    12.      * Close the root web application context. 
    13.      */  
    14.     @Override  
    15.     public void contextDestroyed(ServletContextEvent event) {  
    16.         closeWebApplicationContext(event.getServletContext());  
    17.         ContextCleanupListener.cleanupAttributes(event.getServletContext());  
    18.     }  
    19. }  

     二、ContextLoader剖析

      从上一部分ContextLoaderListener类可以得知,ContextLoader实际执行Spring容器的初始化,Spring整个的配置工作都是在ContextLoader完成的,这里参数ServletContextEvent由web容器提供,不做说明。ContextLoaderListener很好理解,所以我们主要看ContextLoader类。用Maven引入Spring的源码,打开ContextLoader类,类注释的第一行就是

    Xml代码   收藏代码
    1. /**  
    2.  * Performs the actual initialization work for the root application context.  
    3.   ......  
    4. **/  

     用google翻译:实际执行根应用上下文的初始化工作。这里的根应用上下文就是上文所写的WebApplicationContext。我们先看看ContextLoader的时序图

     ContextLoader类initWebApplicationContext()方法

    Java代码   收藏代码
    1. /** 
    2.  * Initialize Spring's web application context for the given servlet context, 
    3.  * using the application context provided at construction time, or creating a new one 
    4.  * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and 
    5.  * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params. 
    6.  * @param servletContext current servlet context 
    7.  * @return the new WebApplicationContext 
    8.  * @see #ContextLoader(WebApplicationContext) 
    9.  * @see #CONTEXT_CLASS_PARAM 
    10.  * @see #CONFIG_LOCATION_PARAM 
    11.  */  
    12. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {  
    13.     //判断ServletContext是否已经存在WebApplication,如果存在则抛出异常  
    14.     if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {  
    15.         throw new IllegalStateException(  
    16.                 "Cannot initialize context because there is already a root application context present - " +  
    17.                 "check whether you have multiple ContextLoader* definitions in your web.xml!");  
    18.     }  
    19.   
    20.     Log logger = LogFactory.getLog(ContextLoader.class);  
    21.     servletContext.log("Initializing Spring root WebApplicationContext");  
    22.     if (logger.isInfoEnabled()) {  
    23.         logger.info("Root WebApplicationContext: initialization started");  
    24.     }  
    25.     long startTime = System.currentTimeMillis();  
    26.   
    27.     try {  
    28.         // Store context in local instance variable, to guarantee that  
    29.         // it is available on ServletContext shutdown.  
    30.         if (this.context == null) {  
    31.             //创建WebApplicationContext(下文有说明)  
    32.             this.context = createWebApplicationContext(servletContext);  
    33.         }  
    34.         if (this.context instanceof ConfigurableWebApplicationContext) {  
    35.             ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;  
    36.             if (!cwac.isActive()) {  
    37.                 // The context has not yet been refreshed -> provide services such as  
    38.                 // setting the parent context, setting the application context id, etc  
    39.                 if (cwac.getParent() == null) {  
    40.                     // 得到根上下文的父上下文,然后设置到根上下文 。一般的web项目parent为空  
    41.                     ApplicationContext parent = loadParentContext(servletContext);  
    42.                     cwac.setParent(parent);  
    43.                 }  
    44.                 //从web.xml加载参数,初始化跟上下文WebApplicationContext,创建bean工厂和bean对象。  
    45.                 //这个过程比较麻烦,下一篇文章专门分析  
    46.                 configureAndRefreshWebApplicationContext(cwac, servletContext);  
    47.             }  
    48.         }  
    49.         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  
    50.   
    51.         ClassLoader ccl = Thread.currentThread().getContextClassLoader();  
    52.         if (ccl == ContextLoader.class.getClassLoader()) {  
    53.             currentContext = this.context;  
    54.         }  
    55.         else if (ccl != null) {  
    56.             currentContextPerThread.put(ccl, this.context);  
    57.         }  
    58.   
    59.         if (logger.isDebugEnabled()) {  
    60.             logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +  
    61.                     WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");  
    62.         }  
    63.         if (logger.isInfoEnabled()) {  
    64.             long elapsedTime = System.currentTimeMillis() - startTime;  
    65.             logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");  
    66.         }  
    67.   
    68.         return this.context;  
    69.     }  
    70.     catch (RuntimeException ex) {  
    71.         logger.error("Context initialization failed", ex);  
    72.         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);  
    73.         throw ex;  
    74.     }  
    75.     catch (Error err) {  
    76.         logger.error("Context initialization failed", err);  
    77.         servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);  
    78.         throw err;  
    79.     }  
    80. }  

         

        在这个方法中ServletContext是由web容器监听器(ContextLoaderListener)提供。首先判断servlectContext中是否已经存在根上下文,如果存在,则抛出异常;否则通过createWebApplicationContext方法创建新的根上下文。然后通过loadParentContext()方法为其设置父上下文。再通过configureAndRefreshWebApplicationContext为根上下文构建bean工厂和bean对象。 最后把上下文存入servletContext,并且存入currentContextPerThread。至此初始化过程完毕,接下来可以获取WebApplicationContext,进而用getBean("bean name")得到bean。

    createWebApplicationContext()方法用来创建根上下文:

    Java代码   收藏代码
    1. protected WebApplicationContext createWebApplicationContext(ServletContext sc) {  
    2.     //从web.xml配置的contextClass参数中获取上下文类名,如果contextClass为空,则使用默认的。  
    3.         //下文有说明  
    4.     Class<?> contextClass = determineContextClass(sc);  
    5.         //根上下文必须是ConfigurableWebApplicationContext的子类,否则抛出异常  
    6.     if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {  
    7.         throw new ApplicationContextException("Custom context class [" + contextClass.getName() +  
    8.                 "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");  
    9.     }  
    10.     //BeanUtils.instantiateClass工具方法,根据类名创建类  
    11.     return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);  
    12. }  
     

    determineContextClass()方法返回根上下文的类名

    Java代码   收藏代码
    1. protected Class<?> determineContextClass(ServletContext servletContext) {  
    2.     //从web.xml获得参数contextClass,在一般的web项目中,此参数为null  
    3.     String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);  
    4.     if (contextClassName != null) {  
    5.         try {  
    6.             return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());  
    7.         }  
    8.         catch (ClassNotFoundException ex) {  
    9.             throw new ApplicationContextException(  
    10.                     "Failed to load custom context class [" + contextClassName + "]", ex);  
    11.         }  
    12.     }  
    13.     else {  
    14.         //获得根上下文WebApplicationContext的默认实现类的类名,defaultStrategies是Properties类型,  
    15.         //在CotnextLoader类开头static语句块中初始化  
    16.         contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());  
    17.         try {  
    18.             return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());  
    19.         }  
    20.         catch (ClassNotFoundException ex) {  
    21.             throw new ApplicationContextException(  
    22.                     "Failed to load default context class [" + contextClassName + "]", ex);  
    23.         }  
    24.     }  
    25. }  
     

    WebApplicationContext默认实现类的类名获取

    Java代码   收藏代码
    1. static {  
    2.     try {  
    3.         //获取当前包下面的ContextLoader.properties文件,文件内容是:  
    4.         //org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext  
    5.         ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);  
    6.         defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);  
    7.     }  
    8.     catch (IOException ex) {  
    9.         throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());  
    10.     }  
    11. }  
  • 相关阅读:
    跳出iframe
    leetcode 225. Implement Stack using Queues
    leetcode 206. Reverse Linked List
    leetcode 205. Isomorphic Strings
    leetcode 203. Remove Linked List Elements
    leetcode 198. House Robber
    leetcode 190. Reverse Bits
    leetcode leetcode 783. Minimum Distance Between BST Nodes
    leetcode 202. Happy Number
    leetcode 389. Find the Difference
  • 原文地址:https://www.cnblogs.com/zkwarrior/p/15549373.html
Copyright © 2011-2022 走看看