tomcat 8.0.36
知识点:
- 动态监听器的好处可以根据环境条件进行选择性添加。
- 静态监听器有七类。
- ServletContextAttributeListener
- ServletRequestListener
- ServletRequestAttributeListener
- HttpSessionIdListener
- HttpSessionAttributeListener
- HttpSessionListener
- 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); }