这个类继承了ContextLoader,实现了ServletContextListener接口。
ServletContextListener接口继承了util包的EventListener接口,EventListener没有任何方法。
这个接口定义了两个方法:
public void contextInitialized(ServletContextEvent sce);
这个方法的注释是在说该方法是通知web应用程序的初始化工作开始了,在所有filter和servlet初始化之前,这个监听器接口的实现类被告知进行上下文的初始化工作。
public void contextDestroyed(ServletContextEvent sce);
这个方法的注释是在说该方法是通知servlet上下文即将关闭。任何filter和servlet都会在这个监听器接口实现类进行上下文销毁之前销毁。
现在来看ContextLoaderListener对这两个方法的实现:
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
这个initWebApplicationContext方法是该监听器实现类的父类ContextLoader类的方法,之后会进入这个类学习源代码。
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
这个closeWebApplicationContext方法也是ContextLoader类的方法。
下面进入ContextCleanupListener,这个监听器实现类也实现了ServletContextListener,只实现了这个接口。
且抽象方法有意义的实现只有一个
@Override
public void contextDestroyed(ServletContextEvent event) {
cleanupAttributes(event.getServletContext());
}
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);
if (attrValue instanceof DisposableBean) {
try {
((DisposableBean) attrValue).destroy();
}
catch (Throwable ex) {
logger.error("Couldn't invoke destroy method of attribute with name '" + attrName + "'", ex);
}
}
}
}
}
contextDestroyed实现里调用了cleanupAttributes方法,这个静态方法在ContextLoaderListener中得到了静态的调用,在ContextCleanupListener的成员方法ContextDestroyed中也被调用,前一个调用还算正常,后一个调用是在成员方法中调用静态方法,觉得有点奇怪。。。但没什么不妥的。。。
来看这个静态方法,先是获取参数ServletContext的所有参数名,返回一个Enumeration接口,这是一个古老的类,现在基本被List实现类替代。得到后遍历这个Enumeration,将所有以“org.springframework”开头的参数名和该参数名对应的值获取,如果参数值属于DisposableBean接口的实现类,则调用该参数值的destroy方法销毁,过程中会抛出异常,然后由logger来输出调试信息。
DisposableBean是一个接口,只有一个destroy方法。