首页 > 编程语言 > 详细

springMVC源码阅读-容器初始化

时间:2020-01-14 14:27:52      阅读:78      评论:0      收藏:0      [点我收藏+]

说明

Root WebApplicationContext 因为容器有父子关系 只是表示是最父级WebApplicationContext   WebApplicationContext是一个接口 默认使用的是XmlWebApplicationContext

1.传统spring mvc配置

<!-- 省略非关键的配置 -->

<!-- [1] Spring配置 -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 指定Spring Bean的配置文件所在目录。默认配置在WEB-INF目录下 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:config/applicationContext.xml</param-value>
</context-param>

<!-- ====================================== -->

<!-- [2] Spring MVC配置 -->
<servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 可以自定义servlet.xml配置文件的位置和名称,默认为WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,如spring-servlet.xml
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring-servlet.xml</param-value> // 默认
    </init-param>
    -->
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

现在spring boot已经不需要配置了。通过自动配置代替了手动配置。但是这些配置还是存在

ContextLoaderListener

作用是在启动tomcat 或者jetty服务器的时候初始化一个Root Spring WebApplicationContext 

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    public ContextLoaderListener() {
    }

    public ContextLoaderListener(WebApplicationContext context) {
        super(context);
    }

    //负责初始化容器
    public void contextInitialized(ServletContextEvent event) {
        this.initWebApplicationContext(event.getServletContext());
    }

    //负责销毁容器
    public void contextDestroyed(ServletContextEvent event) {
        this.closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }
}

initWebApplicationContext

org.springframework.web.context.ContextLoader#initWebApplicationContext

/**
     * WebApplicationContext.class.getName() + ".ROOT"
     * @param servletContext
     * @return
     */
    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        /**
         * <1>
         * 因为初始化后会set到setvletConontext
         * WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE=WebApplicationContext.class.getName() + ".ROOT"
         * 防止重复初始化root 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!");
        } else {
            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 {
                if (this.context == null) {
                    /**
                     * <2>
                     *获得对应的context
                     * 1.servletContext.getInitParameter("contextClass")是否有配置自定义容器
                     * 2.默认是没有获取 所以获得的是org.springframework.web.context.support.XmlWebApplicationContext 解析xml
                     */
                    this.context = this.createWebApplicationContext(servletContext);
                }
                /**
                 * <3>判断是否实现了ConfigurableWebApplicationContext
                  */
                if (this.context instanceof ConfigurableWebApplicationContext) {
                    ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
                    //判断是否激活
                    if (!cwac.isActive()) {
                        //如果没有父节点 则获取sevletContext的rootjie
                        if (cwac.getParent() == null) {
                            /**
                             * <4>
                             * 这里会获取context-param key为locatorFactorySelector 配置的xml
                             * 同时获取析context-param key 为parentContextKey的bean 这个bean必须实现BeanFactory 和ApplicationContext 主要是我们自定义容器
                             * 并以这个容器作为root容器
                             */
                            ApplicationContext parent = this.loadParentContext(servletContext);
                            cwac.setParent(parent);
                        }
                        /**
                         * <5>
                         * 获取servetContext的initParameter key为:contextId值作为初始化容器的id
                         * 如果没有默认是使用org.springframework.web.context.WebApplicationContext:+servletContext.getContextPath()
                         * 解析xml执行初始化
                         */
                        this.configureAndRefreshWebApplicationContext(cwac, servletContext);
                    }
                }
                /**
                 * 将容器设置到servletContext后续我们可以通过servleteContext获取到
                 */
                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 var8) {
                logger.error("Context initialization failed", var8);
                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
                throw var8;
            } catch (Error var9) {
                logger.error("Context initialization failed", var9);
                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9);
                throw var9;
            }
        }
    }

<2>createWebApplicationContext

org.springframework.web.context.ContextLoader#initWebApplicationContext

->

org.springframework.web.context.ContextLoader#createWebApplicationContext

 protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
        Class<?> contextClass = this.determineContextClass(sc);
        /**
         * 判断contextClass 是否是ConfigurableWebApplicationContext类型或者子类型
         * 就是是否能强转
         */
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
        } else {
            //创建对象 并强转为ConfigurableWebApplicationContext
            return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
        }
    }

    protected Class<?> determineContextClass(ServletContext servletContext) {
        /**
         * 是否有配置自定义的context容器
         * 在servletContext获取 key:contextClass
         */
        String contextClassName = servletContext.getInitParameter("contextClass");
        if (contextClassName != null) {
            try {
                //反射创建自定义配置
                return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
            } catch (ClassNotFoundException var4) {
                throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", var4);
            }
        } else {
            /**
             * 获取默认配置 这里是XMLWebApplicationContext
             */
            contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());

            try {
                //反射创建
                return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
            } catch (ClassNotFoundException var5) {
                throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", var5);
            }
        }
    }

<4>

text.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="remoteOssClient" class="com.bozhi.wemall.SimepleBeanFactory">
    </bean>
</beans>

web.xml

<context-param>
    <param-name>locatorFactorySelector</param-name>
    <param-value>classpath:test.xml</param-value>
  </context-param>
  <context-param>
    <param-name>parentContextKey</param-name>
    <param-value>remoteOssClient</param-value>
  </context-param>

 

springMVC源码阅读-容器初始化

原文:https://www.cnblogs.com/LQBlog/p/12191552.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!