zoukankan      html  css  js  c++  java
  • tomcat触发ServletContext初始化监听事件的源码(原创)

    tomcat 8.0.36

    知识点:

    • 动态监听器的好处可以根据环境条件进行选择性添加。
    • 静态监听器有七类。
    1. ServletContextAttributeListener
    2. ServletRequestListener
    3. ServletRequestAttributeListener
    4. HttpSessionIdListener
    5. HttpSessionAttributeListener
    6. HttpSessionListener
    7. ServletContextListener
    • 动态添加的ServletContextListener,其事件源ServletContext缺失插入性等功能。
    • 在触发ServletContext时,不能再动态添加ServletContextListener,但可以动态添加其它类型的监听器。

    获取通过web.xml,web-fragment.xml或者注解等方式配置的监听器集,统称他们为静态监听器集。

    为什么称为静态监听器集,因为他们是固定必须添加进来的,相对于动态来说,动态是可以根据所需或者不同的条件,例如servlet api的版本等因素,进行选择性添加。

    String listeners[] = findApplicationListeners();

    接下来就是定义一个结果集,这个结果集是用于接收监听器实例化后的实例。而实例化的过程也是挺丰富多彩的,例如JNDI注入,POST构造方法调用等,这里就不多叙述了。

    Object results[] = new Object[listeners.length];
    for (int i = 0; i < results.length; i++) {
        String listener = listeners[i];
        results[i] = getInstanceManager().newInstance(listener);
    }

      

    然后把监听器集的实例区分开来,为什么要区分开来?可能是因为事件类型的触发频率要比生命周期的频率高吧,反正能触发就行。

    ArrayList<Object> eventListeners = new ArrayList<>();
    ArrayList<Object> lifecycleListeners = new ArrayList<>();
    for (int i = 0; i < results.length; i++) {
        if ((results[i] instanceof ServletContextAttributeListener)
                || (results[i] instanceof ServletRequestAttributeListener)
                || (results[i] instanceof ServletRequestListener)
                || (results[i] instanceof HttpSessionIdListener)
                || (results[i] instanceof HttpSessionAttributeListener)) {
            eventListeners.add(results[i]);
        }
        if ((results[i] instanceof ServletContextListener)
                || (results[i] instanceof HttpSessionListener)) {
            lifecycleListeners.add(results[i]);
        }
    }

      

    这里就是合并了,当然是与动态监听器集合并,两者合并后就是最终的监听器集。

    在合并生命周期类型的监听器集时,会把动态的ServletContextListener存入noPluggabilityListeners,而noPluggabilityListeners的意思是无插入性监听器集,其用途就在后面。

    for (Object eventListener : getApplicationEventListeners()) {
        eventListeners.add(eventListener);
    }
    setApplicationEventListeners(eventListeners.toArray());
    
    for (Object lifecycleListener : getApplicationLifecycleListeners()) {
        lifecycleListeners.add(lifecycleListener);
        if (lifecycleListener instanceof ServletContextListener) {
            noPluggabilityListeners.add(lifecycleListener);
        }
    }
    setApplicationLifecycleListeners(lifecycleListeners.toArray());

      

    接着,就是关闭一个选项功能,防止程序在触发ServletContextListener事件时,获取ServletContext再次动态添加ServletContextListener。 

    context.setNewServletContextListenerAllowed(false);

      

    再接着,创建了两个事件,这两个事件所用到的ServletContext不一样,一个是功能齐全的ServletContext,另一个是noPluggabilityServletContext,意思是无插入功能的ServletContext,当然就是比功能齐全的ServletContext缺失大部份功能。

    ServletContextEvent event = new ServletContextEvent(getServletContext());
    ServletContextEvent tldEvent = new ServletContextEvent(noPluggabilityServletContext);

      

    最后就是遍历所有ServletContextListener,调用监听方法。如果是动态添加的监听器,是禁止一些操作,所以需要传入无插入性的ServletContext。

    Object instances[] = getApplicationLifecycleListeners();
    for (int i = 0; i < instances.length; i++) {
        if (!(instances[i] instanceof ServletContextListener))
            continue;
        ServletContextListener listener = (ServletContextListener) instances[i];
        try {
            if (noPluggabilityListeners.contains(listener)) {
                listener.contextInitialized(tldEvent);
            } else {
                listener.contextInitialized(event);
            }
        } catch (Throwable t) {
        }
    }

    完整源码:

    public boolean listenerStart() {
        if (log.isDebugEnabled())
            log.debug("Configuring application event listeners");
    
        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];
                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);
        }
    
        ArrayList<Object> eventListeners = new ArrayList<>();
        ArrayList<Object> lifecycleListeners = new ArrayList<>();
        for (int i = 0; i < results.length; i++) {
            if ((results[i] instanceof ServletContextAttributeListener)
                    || (results[i] instanceof ServletRequestAttributeListener)
                    || (results[i] instanceof ServletRequestListener)
                    || (results[i] instanceof HttpSessionIdListener)
                    || (results[i] instanceof HttpSessionAttributeListener)) {
                eventListeners.add(results[i]);
            }
            if ((results[i] instanceof ServletContextListener)
                    || (results[i] instanceof HttpSessionListener)) {
                lifecycleListeners.add(results[i]);
            }
        }
    
        for (Object eventListener : getApplicationEventListeners()) {
            eventListeners.add(eventListener);
        }
        setApplicationEventListeners(eventListeners.toArray());
        
        for (Object lifecycleListener : getApplicationLifecycleListeners()) {
            lifecycleListeners.add(lifecycleListener);
            if (lifecycleListener instanceof ServletContextListener) {
                noPluggabilityListeners.add(lifecycleListener);
            }
        }
        setApplicationLifecycleListeners(lifecycleListeners.toArray());
    
        if (getLogger().isDebugEnabled())
            getLogger().debug("Sending application start events");
    
        getServletContext();
        context.setNewServletContextListenerAllowed(false);
    
        Object instances[] = getApplicationLifecycleListeners();
        if (instances == null || instances.length == 0) {
            return ok;
        }
    
        ServletContextEvent event = new ServletContextEvent(getServletContext());
        ServletContextEvent tldEvent = null;
        if (noPluggabilityListeners.size() > 0) {
            noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext());
            tldEvent = new ServletContextEvent(noPluggabilityServletContext);
        }
        for (int i = 0; i < instances.length; i++) {
            if (!(instances[i] instanceof ServletContextListener))
                continue;
            ServletContextListener listener = (ServletContextListener) instances[i];
            try {
                fireContainerEvent("beforeContextInitialized", listener);
                if (noPluggabilityListeners.contains(listener)) {
                    listener.contextInitialized(tldEvent);
                } else {
                    listener.contextInitialized(event);
                }
                fireContainerEvent("afterContextInitialized", listener);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                fireContainerEvent("afterContextInitialized", listener);
                getLogger().error(sm.getString("standardContext.listenerStart", instances[i].getClass().getName()), t);
                ok = false;
            }
        }
        return (ok);
    }
  • 相关阅读:
    POJ 1434 Fill the Cisterns! (模拟 or 二分)
    Educational Codeforces Round 16 D. Two Arithmetic Progressions (不互质中国剩余定理)
    Educational Codeforces Round 16 E. Generate a String (DP)
    UVALive 3958 Weird Numbers (负进制数)
    HDU 1429 胜利大逃亡(续) (bfs+状态压缩)
    svn 创建本地仓库
    android 动态库死机调试方法 .
    外部博客链接
    反汇编调试Android
    When a java class is load by classloader, where the constant poll be put?
  • 原文地址:https://www.cnblogs.com/hvicen/p/6004819.html
Copyright © 2011-2022 走看看