spring容器监听器

web.xml配置文件

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
    classpath:spring/spring-*.xml
  </param-value>
</context-param>

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

ContextLoaderListener上下文加载监听器

    /**   * servlet容器创建时创建spring容器   */  @Override
    public void contextInitialized(ServletContextEvent event) {
        initWebApplicationContext(event.getServletContext());
    }

    /**
     * servlet容器销毁时注销spring容器
     */
    @Override
    public void contextDestroyed(ServletContextEvent event) {
        closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }

创建spring容器

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 {// 创建上下文,后文详解#1
            if (this.context == null) {
                this.context = createWebApplicationContext(servletContext);
            }
            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
                if (!cwac.isActive()) {
                    if (cwac.getParent() == null) {
                        ApplicationContext parent = loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }            // 刷新上下文包括解析、注册、实例化bean等,后文详解#2
                    configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }       // 将创建好的上下文放到application作用域中
            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;
        }
    }

书接前文#1

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
     // 获得具体的上下文类即XmlWebApplicationContext
        Class<?> contextClass = determineContextClass(sc);
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
                    "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
        }
     // 实例化XmlWebApplicationContext对象,构造函数反射
        return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
    }

书接前文#2

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
        if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
            String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
            if (idParam != null) {
                wac.setId(idParam);
            }
            else {
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                        ObjectUtils.getDisplayString(sc.getContextPath()));
            }
        }

        wac.setServletContext(sc);     // 获得<context-param>标签中的内容
        String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
        if (configLocationParam != null) {
            wac.setConfigLocation(configLocationParam);
        }
        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
        }
      // 检查有没有自定义的上下文
        customizeContext(sc, wac);     // 刷新上下文
        wac.refresh();
    }

接下来是销毁spring容器

public void closeWebApplicationContext(ServletContext servletContext) {
        servletContext.log("Closing Spring root WebApplicationContext");
        try {
            if (this.context instanceof ConfigurableWebApplicationContext) {          // 这里包括广播shutdown事件,销毁bean,销毁BeanFactory等
                ((ConfigurableWebApplicationContext) this.context).close();
            }
        }
        finally {
            ClassLoader ccl = Thread.currentThread().getContextClassLoader();
            if (ccl == ContextLoader.class.getClassLoader()) {
                currentContext = null;
            }
            else if (ccl != null) {
                currentContextPerThread.remove(ccl);
            }        // application作用域中去除上下文
            servletContext.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
            if (this.parentContextRef != null) {
                this.parentContextRef.release();
            }
        }
    }
static void cleanupAttributes(ServletContext sc) {
        Enumeration<String> attrNames = sc.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = attrNames.nextElement();
            if (attrName.startsWith("org.springframework.")) {
                Object attrValue = sc.getAttribute(attrName);          // 对于实现了DisposableBean接口的bean,容器销毁时执行destroy方法
                if (attrValue instanceof DisposableBean) {
                    try {
                        ((DisposableBean) attrValue).destroy();
                    }
                    catch (Throwable ex) {
                        logger.error("Couldn‘t invoke destroy method of attribute with name ‘" + attrName + "‘", ex);
                    }
                }
            }
        }
    }
时间: 2024-10-10 19:17:39

spring容器监听器的相关文章

监听器如何获取Spring配置文件(加载生成Spring容器)

Spring容器是生成Bean的工厂,我们在做项目的时候,会用到监听器去获取spring的配置文件,然后从中拿出我们需要的bean出来,比如做网站首页,假设商品的后台业务逻辑都做好了,我们需要创建一个监听器,在项目启动时将首页的数据查询出来放到application里,即在监听器里调用后台商品业务逻辑的方法,也就是说我们需要在监听器里获取Spring中配置的相应的bean.先把监听器创建出来: 1. 创建InitDataListener 创建一个监听器InitDataListener继承Serv

WEB容器监听器详解 ServletContextListener

WEB容器监听器ServletContextListener主要用来监听容器启动和 销毁的时候需要做一些操作,就可以使用这个监听器来做. ServletContextListener在Spring启动前启动. 我们实现一个简单的监听器,需要继承接口ServletContextListener: * 一个测试的监听器例子 * @author zhuli * @date 2014-7-26 */ public class TestContextLister implements ServletCon

基于纯Java代码的Spring容器和Web容器零配置的思考和实现(3) - 使用配置

经过<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(1) - 数据源与事务管理>和<基于纯Java代码的Spring容器和Web容器零配置的思考和实现(2) - 静态资源.视图和消息器>两篇博文的介绍,我们已经配置好了Spring所需的基本配置.在这边博文中,我们将介绍怎么使用这些配置到实际项目中,并将web.xml文件替换为一个Java类. 我们使用Java代码来配置Spring,目的就是使我们的这些配置能够复用,对于这些配置的复用,我们采用继承和引入来实现

(一)Spring容器相关操作

一.spring事件 spring的事件有如下两个成员. 1.ApplicationEvent,容器事件,由容器发布 2.ApplicationListener 监听器,可以由容器中的任何监听器Bean担任 (1)先顶一个spring的容器事件: package cn.study.basic; import org.springframework.context.ApplicationEvent; public class EmailEvent extends ApplicationEvent

BeanFactory到WebApplicationContext的结构 以及bean和spring容器的关系

BeanFactory: Ioc 容器 ApplicationContext: Spring容器 WebApplicationContext需要ServletContext实例,也就是说它必须在拥有Web 容器的 前提下才能完成启动的工作. Spring分别提供了用于启动WebApplicationContext的 Servlet和 Web容器监听器: org.springframework.web.context.ContextLoaderServlet: org.springframewor

spring源码学习之:spring容器的applicationContext启动过程

Spring 容器像一台构造精妙的机器,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式进行工作.如果我们将Spring容器比喻为一辆汽车,可以将 BeanFactory看成汽车的发动机,而ApplicationContext则是 整辆汽车,它不但包括发动机,还包括离合器.变速器以及底盘.车身.电气设备等其他组件.在ApplicationContext内,各个组件按部就班. 有条不紊地完成汽车的各项功能. ApplicationContext内部封装 了一个BeanFactory对象

Spring笔记——2.使用Spring容器

Spring有连个核心接口:BeanFactory和ApplicationContext.而ApplicationContext是BeanFactory的子接口,都可以代表Spring容器,用于产生管理Bean们.我们经常使用ApplicationContext以及它的实现类ClassPathXmlApplicationContext.当创建ApplicationContext时,会实例化所有的单例Bean,花销较大,但之后性能较好.如果为bean设置lazy-init为true,则不会在开始初

Spring容器-ApplicationContext的启动过程

转载自: http://blog.163.com/[email protected]/blog/static/118777042009410248557/ 这片博客信息量很大,言简意赅.简明扼要地说清楚了Spring容器的启动过程,前面红色的“打比方”可以忽略... Spring容器像一台构造精妙的机器,我们通过配置文件向机器传达控制信息,机器就能够按照设定的模式进行工作.如果我们将Spring容器比喻为一辆汽车,可以将BeanFactory看成汽车的发动机,而ApplicationContex

Spring-----4、使用Spring容器

Spring有两个核心接口:BeanFactory和ApplicationContext(BeanFactory的子接口):他们都可代表Spring容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean:Bean是Spring管理的基本单位,在基于Spring的JavaEE应用中,所有的组件都被当成Bean处理,包括数据源.Hibernate的SesisonFactoy.事务管理器等 应用中的所有组件,都处于Spring的管理下,都被Spring以Bean的方式管理,Spring