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); }