zoukankan      html  css  js  c++  java
  • ContextLoaderListener

    基本概念:

    servletContext:http://blog.csdn.net/yjw757174266/article/details/45072975

     

    1、  使用ContextLoaderListener监听器的意义:

    a) 为了在servlet容器启动时,就加载applicationContext.xml(spring核心配置文件)配置文件,实例化其中配置的bean类。

    b)避免在使用spring容器获取bean时,重复加载配置文件。

    2、  spring版本:4.2.4

    3、  配置方式:

    a)在web.xml文件中编写监听器,并配置全局的上下文变量,提供spring核心配置文件,代码如下:

    <listener>

    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

    <context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>classpath:applicationContext.xml</param-value>

    </context-param>

    b) 如果配置了监听器,那么获取bean的方式就要相应的改变一下,代码如下:

    1、ServletContext servletContext = ServletActionContext.getServletContext();

    2、WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);

    3、XXXService cs = (XXXService) context.getBean("XXXService");

    4、cs.save();

    c)我们先不管为什么WebApplicationContext对象与ApplicationContext对象一样能获取bean对象,我们此处探究的是,为什么配置了监听器,我们就能从servletcontext中取得WebApplicationContext对象。

    4、  源码分析:

    a)首先进入org.springframework.web.context.ContextLoaderListener 源码:代码如下:

    //: org.springframework.web.context.ContextLoaderListener.java

    package org.springframework.web.context;

    import javax.servlet.ServletContextEvent;

    import javax.servlet.ServletContextListener;

    public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

             public ContextLoaderListener() {

             }

             public ContextLoaderListener(WebApplicationContext context) {

                       super(context);

             }

             @Override

             public void contextInitialized(ServletContextEvent event) {

                       initWebApplicationContext(event.getServletContext());

             }

             @Override

             public void contextDestroyed(ServletContextEvent event) {

                       closeWebApplicationContext(event.getServletContext());

                       ContextCleanupListener.cleanupAttributes(event.getServletContext());

             }

    }

    b)我们可以看到此处继承了 ServletContextListener 接口,实现两个方法(contextInitialized、contextDestroyed),在servlet容器启动和销毁的时候做一些事情。

    c) 在ContextLoaderListener监听器这个场景下,contextInitialized方法中会调用ContextLoader 类中的initWebApplicationContext方法,实例化出一个WebApplicationContext对象,此方法接收一个servletContext对象,此对象由Servlet容器传入。

    5、  然后我们转到initWebApplicationContext方法中:代码如下:

    //: org.springframework.web.context.ContextLoader.java

    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {

             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;

             }

    }

     

    a)  this.context = createWebApplicationContext(servletContext);首先我们看这句代码,同样我们先不谈就它是怎么创建的,我们见名知意,就是根据servletContext参数,创建一个WebApplicationContext对象,并赋值给ContextLoader类中的内部变量 context。

    b) servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); 紧接着将已经赋值的context变量,通过一个的标识名称放入servletContext对象中。

    c) 看到这里,我想大家都知道为什么可以从ServletContex中取出WebApplicationContext对象了吧?

    6、  接着我们分析在客户端获取WebApplicationContext对象的代码,再copy一份到这里:

    1、ServletContext servletContext = ServletActionContext.getServletContext();

    2、WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);

    3、XXXService cs = (XXXService) context.getBean("XXXService");

    4、cs.save();

    a) 首先,我们从struts2框架提供的类中,获取servletContext对象。

    b) 之后通过WebApplicationContextUtil类中的getWebApplicationContext方法,从servletContext对象中,将WebApplicationContext对象取出:我们进入方法:

    public static WebApplicationContext getWebApplicationContext(ServletContext sc) {

             return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);  // 此处标识与存入时的一致

    }

    c) 进而转入如下方法:

    public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {

             Assert.notNull(sc, "ServletContext must not be null");

             Object attr = sc.getAttribute(attrName);

             if (attr == null) {

                       return null;

             }

             if (attr instanceof RuntimeException) {

                       throw (RuntimeException) attr;

             }

             if (attr instanceof Error) {

                       throw (Error) attr;

             }

             if (attr instanceof Exception) {

                       throw new IllegalStateException((Exception) attr);

             }

             if (!(attr instanceof WebApplicationContext)) {

                       throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);

             }

             return (WebApplicationContext) attr;

    }

    d) 我们根据上面的两句代码: Object attr = sc.getAttribute(attrName);  / return (WebApplicationContext) attr; 不难看出,将WebApplicationContext对象,从servletcontext对象中取出,强制转换并返回。

    7、至此

    a) 我们就取得了WebApplicationContext对象,并可以使用该对象来获取bean。而WebApplicationContext对象存放在servletcontext对象中,而servletcontext对象会一直存在于内存中,除非关闭servlet容器。这样就保证了只存在一份WebApplicationContext对象在内存中,同时也就保证了spring核心配置文件只会被加载一次。

  • 相关阅读:
    dedecmsV5.7和discuz!X3.4整合之后免激活登陆
    dedecms织梦文章微信分享带缩略图与简介
    关于PHP的mkdir函数
    关于discuz的fap.php 漏洞问题
    discuzX3.4安装之后,没有任何样式怎么办?
    阿里云 RDS for MySQL支持什么引擎
    PHP随机生成要求位数个字符(大小写字母+数字)
    PHP json_decode为什么将json字符串转成数组是对象格式?
    PHP实用的功能函数
    css实现三角形图标
  • 原文地址:https://www.cnblogs.com/hfultrastrong/p/7838587.html
Copyright © 2011-2022 走看看