tomcat触发ServletContext初始化监听事件的源码(原创)
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);
}
tomcat触发ServletContext初始化监听事件的源码(原创)的更多相关文章
- memcached(二)事件模型源码分析
memcachedd事件模型 在memcachedd中,作者为了专注于缓存的设计,使用了libevent来开发事件模型.memcachedd的时间模型同nginx的类似,拥有一个主进行(master) ...
- jquery的监听事件和触发事件
监听事件 $(selector).on('Event me',function(e){ //do something }) 触发事件 $(selector).trigger('Event name') ...
- Vue自定义事件,$on(eventName) 监听事件,$emit(eventName) 触发事件
<!--自定义事件 使用 $on(eventName) 监听事件 使用 $emit(eventName) 触发事件--> <div id="app15"> ...
- vue 中监听窗口发生变化,触发监听事件, window.onresize && window.addEventListener('resize',fn) ,window.onresize无效的处理方式
// 开始这样写,不执行 window.onresize = function() { console.log('窗口发生变化') } // 改成window监听事件 window.addEventL ...
- javascript事件有哪些?javascript的监听事件
事件类型: 1.界面事件 onload:描述文档,图片,css已经frame,object加载完毕时触发,window.onload window.onload = function(){ //代表图 ...
- spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情
<spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...
- zookeeper 监听事件 PathChildrenCacheListener
zookeeper 监听事件 PathChildrenCacheListener PathChildrenCacheListener一次父节点注册,监听每次子节点操作,不监听自身和查询. 1.测试类: ...
- zookeeper 监听事件 NodeCacheListener
zookeeper 监听事件 NodeCacheListener NodeCacheListener一次注册,每次监听,但是监听不到操作类型,不知道是增加?删除?还是修改? 1.测试类: packag ...
- 关于AngularJs中监听事件及脏循环的理解
可能很多刚入行或者刚学习的前端对于AngularJs中的一些事件或者概念感觉不理解或者没有思路,今天让我们一起来剖析一下AngularJs中的一些事件. AngularJs中对于的监听事件会用到一个s ...
随机推荐
- [原] XAF How can I change XafDisplayNameAttribute dynamically
void ViewControlsCreated(object sender, EventArgs e) { foreach (StringPropertyEditor item in view.Ge ...
- wp学习计划!
对wp兴趣很大,可真正学习时,目的性就很不明确了,其实这有两大问题阻碍着,一是自身的基础还不够扎实,二是学习资料不好找,前者只能慢慢积累,而后者却是可以改变的,现在我的主阵营是channel 9上的w ...
- 打印文本中的所有单词,并且打印每个单词出现的行号,非实义单词不考虑(TCPL,练习6-3)
建立一棵二叉树,每个接单存放单词以及指向一个链表的指针,以及指向左右节点的指针.链表内存放行号以及指向下一个链表节点的指针. 每录入一个单词,先寻找二叉树,再寻找它的链表,分别将单词和行号插入二叉树和 ...
- WebLogic 8.1 部署问题记录
1.weblogic 8.1 不支持jdk1.4以上的版本,所以,如果在项目中用jdk1.4以上的版本编译之后的class直接部署到weblogic8.1 服务器上会报错,报错信息一般包括如下: Cl ...
- Vmware配置
1.网络 四种连接模式的区别:http://www.cnblogs.com/awpatp/archive/2009/07/24/1530471.html 如果网卡使用Nat模式,则需要启动服务: VM ...
- dex分包变形记
腾讯Bugly特约作者:李金涛 一.背景 就在项目灰度测试前不久,爆出了在 Android 3.0以下手机上安装时出现 INSTALL _ FAILED_DEXOPT,导致安装失败.这一问题意味着项目 ...
- 微软颜龄Windows Phone版开发小记
随着微软颜龄中文网cn.how-old.net的上线,她也顺势来到了3大移动平台. 用户在微软颜龄这一应用中选择一张包含若干人脸的照片,就可以通过云计算得到他们的性别和年龄. 今天我们就和大家分享一下 ...
- 使用SQLIO测试磁盘性能
SQLIO 是一个用于测试存储系统能力的命令行工具,用以获取存储系统相关的性能指标,以判断系统的 I/O 处理能力. 在微软的网站可以下载 SQLIO 的安装包,安装后目录中会出现如下文件: EULA ...
- 【C语言学习】《C Primer Plus》第4章 字符串和格式化输入/输出
学习总结 1.String str=”hello world!”;(Java),char[20]=” hello world!”;(C).其实Java字符串的实现,也是字符数组. 2.字符串的尾部都会 ...
- Aoite 系列(01) - 比 Dapper 更好用的 ORM
Aoite 是一个适于任何 .Net Framework 4.0+ 项目的快速开发整体解决方案.Aoite.Data 适用于市面上大多数的数据库提供程序,通过统一封装,可以在日常开发中简单便捷的操作数 ...