web监听器解析

监听器是web三大组件之一,事件监听机制如下:

  • 事件:某个事件,如果初始化上下文
  • 事件源:事件发生的地方
  • 监听器:一个对象,拥有需要执行的逻辑
  • 注册监听:将事件、事件源、监听器绑定在一起。当事件源发生某个事件后,将事件传递给监听器,监听器执行相应代码逻辑

添加监听器

在web项目中的web.xml配置文件中一般有这样一段代码,ContextLoaderListener是一个监听器实现了ServletContextListener接口。在后续解析web.xml文件中会添加到StandardContext上下文的applicationListeners数组中,之后当上下文开启后会根据监听器的全限定名构造监听器实例并初始化监听器。

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

web监听器解析

ServletContextListener能在web应用程序初始化的过程中收到通知,在过滤器filter和servlet初始化之前执行相应的上下文初始化逻辑,也能在servlet上下文关闭时收到通知,在过滤器filter和servlet销毁后执行相应的上下文销毁逻辑。

public interface ServletContextListener extends EventListener {

    /**
     ** Notification that the web application initialization process is starting.

     * All ServletContextListeners are notified of context initialization before
     * any filter or servlet in the web application is initialized.

     * @param sce Information about the ServletContext that was initialized
     */
    public void contextInitialized(ServletContextEvent sce);

    /**
     ** Notification that the servlet context is about to be shut down. All
     * servlets and filters have been destroy()ed before any
     * ServletContextListeners are notified of context destruction.

     * @param sce Information about the ServletContext that was destroyed
     */
    public void contextDestroyed(ServletContextEvent sce);
}

初始化监听器

当StandardContext上下文启动后会调用 listenerStart方法,该方法初始化所有添加到context的监听器,之后构建事件执行ServletContextListener类型的监听器 listener.contextInitialized(event);初始化上下文

public boolean listenerStart() {

    if (log.isDebugEnabled()) {
        log.debug("Configuring application event listeners");
    }

    // Instantiate the required listeners
    // &#x6CE8;&#x518C;&#x76D1;&#x542C;&#x5668;&#x7684;&#x5168;&#x9650;&#x5B9A;&#x540D;&#x6570;&#x7EC4;
    String listeners[] = findApplicationListeners();
    Object results[] = new Object[listeners.length];
    boolean ok = true;
    for (int i = 0; i < results.length; i++) {
        if (getLogger().isDebugEnabled()) {
            getLogger().debug(" Configuring event listener class '" +
                listeners[i] + "'");
        }
        try {
            String listener = listeners[i];
            // &#x5B9E;&#x4F8B;&#x5316;&#x76D1;&#x542C;&#x5668;
            results[i] = getInstanceManager().newInstance(listener);
        } catch (Throwable t) {
            t = ExceptionUtils.unwrapInvocationTargetException(t);
            ExceptionUtils.handleThrowable(t);
            getLogger().error(sm.getString(
                    "standardContext.applicationListener", listeners[i]), t);
            ok = false;
        }
    }
    if (!ok) {
        getLogger().error(sm.getString("standardContext.applicationSkipped"));
        return false;
    }

    // Sort listeners in two arrays
    List<object> eventListeners = new ArrayList<>();
    List<object> lifecycleListeners = new ArrayList<>();
    // &#x5206;&#x7EC4; &#x533A;&#x5206;&#x4E8B;&#x4EF6;&#x76D1;&#x542C;&#x5668;&#x548C;&#x751F;&#x547D;&#x5468;&#x671F;&#x76D1;&#x542C;&#x5668;
    // ServletContextListener&#x4E3A;&#x751F;&#x547D;&#x5468;&#x671F;&#x76D1;&#x542C;&#x5668;
    for (Object result : results) {
        if ((result instanceof ServletContextAttributeListener)
                || (result instanceof ServletRequestAttributeListener)
                || (result instanceof ServletRequestListener)
                || (result instanceof HttpSessionIdListener)
                || (result instanceof HttpSessionAttributeListener)) {
            eventListeners.add(result);
        }
        if ((result instanceof ServletContextListener)
                || (result instanceof HttpSessionListener)) {
            lifecycleListeners.add(result);
        }
    }

    // Listener instances may have been added directly to this Context by
    // ServletContextInitializers and other code via the pluggability APIs.

    // Put them these listeners after the ones defined in web.xml and/or
    // annotations then overwrite the list of instances with the new, full
    // list.

    // &#x8BBE;&#x7F6E;&#x5E94;&#x7528;&#x7684;&#x4E8B;&#x4EF6;&#x76D1;&#x542C;&#x5668;&#x548C;&#x751F;&#x547D;&#x5468;&#x671F;&#x76D1;&#x542C;&#x5668;
    eventListeners.addAll(Arrays.asList(getApplicationEventListeners()));
    setApplicationEventListeners(eventListeners.toArray());
    for (Object lifecycleListener: getApplicationLifecycleListeners()) {
        lifecycleListeners.add(lifecycleListener);
        if (lifecycleListener instanceof ServletContextListener) {
            noPluggabilityListeners.add(lifecycleListener);
        }
    }
    setApplicationLifecycleListeners(lifecycleListeners.toArray());

    // Send application start events

    if (getLogger().isDebugEnabled()) {
        getLogger().debug("Sending application start events");
    }

    // Ensure context is not null
    getServletContext();
    // &#x4E0D;&#x5141;&#x8BB8;&#x8BBE;&#x7F6E;&#x65B0;&#x7684;&#x76D1;&#x542C;
    context.setNewServletContextListenerAllowed(false);

    Object instances[] = getApplicationLifecycleListeners();
    if (instances == null || instances.length == 0) {
        return ok;
    }

    // &#x6839;&#x636E;servlet&#x4E0A;&#x4E0B;&#x6587;&#x6784;&#x5EFA;ServletContextEvent&#x4E8B;&#x4EF6;
    ServletContextEvent event = new ServletContextEvent(getServletContext());
    ServletContextEvent tldEvent = null;
    if (noPluggabilityListeners.size() > 0) {
        noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext());
        tldEvent = new ServletContextEvent(noPluggabilityServletContext);
    }
    // &#x8C03;&#x7528;ServletContextListener&#x76D1;&#x542C;&#x5668;
    for (Object instance : instances) {
        if (!(instance instanceof ServletContextListener)) {
            continue;
        }
        ServletContextListener listener = (ServletContextListener) instance;
        try {
            fireContainerEvent("beforeContextInitialized", listener);
            if (noPluggabilityListeners.contains(listener)) {
                listener.contextInitialized(tldEvent);
            } else {
                // &#x5BB9;&#x5668;&#x4E0A;&#x4E0B;&#x6587;&#x521D;&#x59CB;&#x5316; &#x8C03;&#x7528;&#x76D1;&#x542C;&#x5668;contextInitialized&#x65B9;&#x6CD5;&#x521D;&#x59CB;&#x5316;
                listener.contextInitialized(event);
            }
            fireContainerEvent("afterContextInitialized", listener);
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            fireContainerEvent("afterContextInitialized", listener);
            getLogger().error(sm.getString("standardContext.listenerStart",
                    instance.getClass().getName()), t);
            ok = false;
        }
    }
    return ok;

}</object></object>

ContextLoaderListener解析

ContextLoaderListener上下文加载监听器有什么作用呢?它是spring的一个类,主要用来初始化spring容器XmlWebApplicationContext。我们也可以用contextClass指定上下文类使用支持扫描注解的AnnotationConfigWebApplicationContext,如下:

<context-param>
    <param-name>contextClass</param-name>
    <param-value>
        org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
</context-param>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.monian.study.config.AppConfig</param-value>
</context-param>
@Configuration
@ComponentScan(basePackages = "com.monian.study")
@PropertySource(value = {"classpath:oss.properties", "classpath:datasource.properties"})
public class AppConfig {

}

当执行 contextInitialized方法时初始化根web应用上下文:根据contextClass配置的上下文类AnnotationConfigWebApplicationContext若没有配置则默认XmlWebApplicationContext进行类加载后再通过反射实例化web容器,接着对web容器容器id更新、配置文件路径设置等初始化操作,最后调用refresh()方法刷新容器,将 AppConfig 作为初始java配置文件,扫描basePackages包下的所有类解析spring bean构建spring容器

/**
* Initialize the root web application context.

*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    // ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE&#x5C5E;&#x6027;&#x4E3A;&#x7A7A;&#xFF0C;&#x4E0D;&#x4E3A;&#x7A7A;&#x8BF4;&#x660E;&#x53EF;&#x80FD;&#x6709;&#x91CD;&#x590D; &#x62A5;&#x9519;
    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.
        // &#x521B;&#x5EFA;contextClass&#x6307;&#x5B9A;&#x7684;web&#x4E0A;&#x4E0B;&#x6587;
        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.
                    // &#x5982;&#x679C;&#x6709;&#x7236;&#x5BB9;&#x5668;&#x7684;&#x8BDD;&#x8FDB;&#x884C;&#x8BBE;&#x7F6E;
                    ApplicationContext parent = loadParentContext(servletContext);
                    cwac.setParent(parent);
                }
                // &#x914D;&#x7F6E;&&#x5237;&#x65B0;&#x5BB9;&#x5668;
                configureAndRefreshWebApplicationContext(cwac, servletContext);
            }
        }
        // &#x5C06;&#x5BB9;&#x5668;&#x4E0A;&#x4E0B;&#x6587;&#x8BBE;&#x7F6E;&#x5230;servletContext&#x7684;ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE&#x5C5E;&#x6027;&#x4E2D;
        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;
    }
}
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
    // &#x9ED8;&#x8BA4;&#x76F8;&#x540C; &#x91CD;&#x65B0;&#x8BBE;&#x7F6E;&#x5BB9;&#x5668;&#x4E0A;&#x4E0B;&#x6587;&#x6807;&#x8BC6;
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        // The application context id is still set to its original default value
        // -> assign a more useful id based on available information
        // &#x4ECE;servlet&#x4E0A;&#x4E0B;&#x6587;&#x83B7;&#x53D6;contextId
        String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
        if (idParam != null) {
            wac.setId(idParam);
        }
        else {
            // Generate default id... &#x8BBE;&#x7F6E;&#x4E0A;&#x4E0B;&#x6587;id
            // WebApplicationContext:+contextPath
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                    ObjectUtils.getDisplayString(sc.getContextPath()));
        }
    }

    // &#x8BBE;&#x7F6E;servlet&#x4E0A;&#x4E0B;&#x6587;
    wac.setServletContext(sc);
    // &#x83B7;&#x53D6;&#x914D;&#x7F6E;&#x6587;&#x4EF6;&#x8DEF;&#x5F84;contextConfigLocation
    String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
    // &#x8BBE;&#x7F6E;contextConfigLocation
    if (configLocationParam != null) {
        wac.setConfigLocation(configLocationParam);
    }

    // The wac environment's #initPropertySources will be called in any case when the context
    // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    // use in any post-processing or initialization that occurs below prior to #refresh
    // &#x521D;&#x59CB;&#x5316;&#x73AF;&#x5883;&#x914D;&#x7F6E;
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        // &#x521D;&#x59CB;&#x5316;servlet&#x5C5E;&#x6027;&#x8D44;&#x6E90;
        ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
    }

    // &#x81EA;&#x5B9A;&#x4E49;&#x521D;&#x59CB;&#x5316;
    customizeContext(sc, wac);

    // &#x5237;&#x65B0;web&#x5BB9;&#x5668; &#x521D;&#x59CB;&#x5316;bean
    wac.refresh();
}

Original: https://www.cnblogs.com/monianxd/p/16617576.html
Author: 默念x
Title: web监听器解析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/621838/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Python–module–OS

    csharp;gutter:true; import os a = os.getcwd() # 获取当前的操作目录 b = os.chdir("C:\Users&quot…

    数据库 2023年6月9日
    0124
  • Nginx 配置参数优化

    nginx 配置参数优化 nginx作为高性能web服务器,即使不特意调整配置参数也可以处理大量的并发请求。以下的配置参数是借鉴网上的一些调优参数,仅作为参考,不见得适于你的线上业…

    数据库 2023年6月6日
    0121
  • 不同分层中的对象的使用

    在项目中,控制层,业务层,数据层,视图层(返回值)。中分别使用了的对象,暂时不太理解这样做的好处,先记录下来。 如下: 控制层:也可以叫做入参对象, UserQuery userQ…

    数据库 2023年6月11日
    089
  • [spring]spring注解开发

    8.使用注解开发 1.bean spring4以后,注解依赖于aop包,确保你的lib中有它 确保开启了使用注解 2.组件代替bean实现自动注入 在配置文件中自动扫描包下的所有类…

    数据库 2023年6月16日
    0107
  • JDBC概述

    JDBC概述 JDBC(Java DataBase Connectivity),它是一种用于执行 SQL语句的 JavaAPI。通过使用JDBC就可以使用 相同的API访问 不同的…

    数据库 2023年6月16日
    0106
  • Typora加七牛云实现实时图片自动上传

    Typora加七牛云实现实时图片自动上传 前言: ​ Typora是一款轻便简洁的Markdown编辑器,支持即时渲染技术,这也是与其他Markdown编辑器最显著的区别.重点是免…

    数据库 2023年6月9日
    0220
  • Mac IDEA 最常用快捷键(详解版)

    学习背景 公司同事让我提供一个简单的 rpc 接口,然后他坐在我旁边看着我写,写的过程中他不断打断我,比如我在代码换行时,如果光标不在下一行行首或者这行的行尾,我就会先移动光标到行…

    数据库 2023年6月6日
    0125
  • Dubbo源码(二)-SPI源码

    假设你已经知道Dubbo SPI的使用方式,不知道的请出门左转: Dubbo源码地址: 本文使用版本:2.6.x 获取所有的拓展类 Dubbo SPI 的相关逻辑被封装在了 Ext…

    数据库 2023年6月11日
    0100
  • pg substring 正则提取子串

    官方案例: 测试: posted @2022-02-08 19:48 cheng_blog 阅读(218 ) 评论() 编辑 Original: https://www.cnblo…

    数据库 2023年6月16日
    0118
  • IO流学习笔记

    IO流就是以流的方式进行输入输出 IO 流 Input Output Stream(输入输出流):以流的方式进行输入输出与文件或数据交互的内容称为 IO 流,在 JDK 中 jav…

    数据库 2023年6月11日
    0118
  • 【必知必会】手把手教你配置MySQL环境变量——图文详解

    一、先决条件 假设我们已经成功安装MySQL数据库。如果还有小伙伴不知道如何安装MySQL数据库,可以在本文下留言,留言数超20,则出一期”手把手教你安装MySQL数据…

    数据库 2023年6月14日
    090
  • 太赞了!墙裂推荐这款网页版 Nginx 配置生成器,好用到爆!

    之前民工哥也给大家介绍过一款Nginx配置生成器:强大!Nginx 配置在线一键生成”神器”,不太了解的人可以去看一看。 最近民工哥又发现一款好用的网页版开…

    数据库 2023年6月9日
    0199
  • flowable 查询、完成、作废、删除 任务

    /** * 查询我的任务 * from fhadmin.cn * @param USERNAME * @return 返回任务列表 */ protected List findMy…

    数据库 2023年6月6日
    0252
  • 2. 函数

    404. 抱歉,您访问的资源不存在。 可能是URL不正确,或者对应的内容已经被删除,或者处于隐私状态。 [En] It may be that the URL is incorre…

    数据库 2023年5月24日
    0111
  • javaWeb知识点大集合!!!

    pom文件: 4.0.0 org.example javaweb_maven 1.0-SNAPSHOT war UTF-8 1.7 1.7 com.github.pagehelpe…

    数据库 2023年6月16日
    0112
  • 数据库设计的十个最佳实践

    数据库是应用及计算机的核心元素,负责存储运行软件应用所需的一切重要数据。为了保障应用正常运行,总有一个甚至多个数据库在默默运作。我们可以把数据库视为信息仓库,以结构化的方式存储了大…

    数据库 2023年5月24日
    0138
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球