在上一篇分析Tomcat是如何初始化servlet文章中有谈到Lifecycle的观察者模式,但没有深入解释。其实在StandardContext的fireLifecleEvent方法中就是一个将事件向监听器传递的动作:
如下图所示:
protected void fireLifecycleEvent(String type, Object data) {
// 构造一个事件:事件源=》Lifecycle组件,事件类型/数据由传入参数决定
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
// 通过for循环将该事件通知给该lifecycle组件所持有的全部监听者
listener.lifecycleEvent(event);
}
}
在这里我们预先给出一个结论:StandardContext的监听器Listener是ContextConfig
这里先不做解释,暂时记住这个结论就可以。
然后给出预备知识:什么叫观察者模式的事件监听机制?
一般来讲:
事件监听机制如下:
- 事件源:事件发生的地方
- 事件:在事件源发生的事件,比如:初始化上下文
- 监听器:监听事件源的一个对象,拥有接收到事件时需要执行的逻辑
- 注册监听:将事件、事件源、监听器绑定在一起。当事件源发生某个事件后,将事件传递给监听器,监听器执行相应代码逻辑
在tomcat中所有继承LifecycleBase的组件都是事件源
下面我们来分析ContextConfig监听器是如何创建的,然后怎样绑定到StandardContext的
然后重新回到tomcat源码:
先定位到org.apache.catalina.startup.Catalina中load方法内的createStartDigester方法:
然后进入createStartDigester方法并定位到addRuleSet入参是new ContextRuleSet的部分:
接着进入Digester类的addRuleSet方法中的ruleSet.addRuleInstances(this)部分:
这里说一下: digester是一个独立的开源项目,最初是给struct解析xml文件,后来引入到tomcat解析server.xml文件,当然实际上digester能做的远不止这些,下面继续进入addRuleInstances方法:
可以看到RuleSet实际是一个接口,下面有很多实现类,但是参考之前的代码:前面addRuleSet入参是new ContextRuleSet,所以这里的实现类应该选择ContextRuleSet
进入到ContextRuleSet类后定位到addRuleInstances方法中digester.addRule方法中跟ContextConfig相关的代码:
从这里我们大致已经可以推断:StandardContext已经跟ContextConfig监听器绑定了。
为什么这么说呢:
1. 这里的LifecycleListenerRule的字眼已经很明显了:监听器规则嘛
2. prefix是ContextRuleSet类的属性,实际由构造器参数传入,回顾到catalina代码中的createStartDigester方法的addRuleSet代码段
digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
我们可以很容易推断:这里的prefix就是"Server/Service/Engine/Host/"
然后prefix + "Context"一拼接就成了"Server/Service/Engine/Host/Context"
这不就是StandardContext吗。 因为StandardContext是Context容器的具体实现类。
其实分析到了这一步就差不多了。
但是为了进一步充分证明这个推断,我们继续往下走,定位到digester.addRule方法:
rule其实就是上面的ContextConfig监听器Listener。
备注:
继承关系: LifecycleListenerRule => org.apache.tomcat.util.digester.Rule
继承关系:ContextRuleSet=》RuleSetBase =》RuleSet
rule.setDigester就是一个set方法,把入参pattern赋值给rule的digester属性,这里就不多说了:
然后回到digester的addRule方法,而getRules返回的Rules,这里需要重点看一下Rules的add方法:
可以看到add方法是一个接口,然后接着看它的实现类:
到这里就基本看的很清楚了: add方法的实现类是RulesBase,它的add方法有两个入参:
一个是pattern:其实就是被监听的组件,具体在这里就是StandardContext,
一个是Rule: 就是组件的监听器,具体在这里就是ContextConfig
因为一个组件的监听器可能不止一个,所以这里的监听器实际是一个List集合
然后查询监听器采用的是缓存机制:缓存实际是一个HashMap: key是组件名,value是组件的监听器集合List, 首先从缓存中查找,找不到就存到缓存中,同时更新缓存
至此: StandardContext的监听器ContextConfig的绑定过程已经全部分析完毕