Tomcat学习笔记(五)
生命周期事件
Catalina包含有很多组件。当Catalina启动时,这些组件也会启动,同样,当Catalina关闭时,这些组件也随之关闭,通过实现org.apache.catalina.Lifecycle接口,可以达到统一启动/关闭这些组件的效果。
实现Lifecycle接口的组件可以触发一个或多个下面的事件:BEFORE_START_EVENT、START_EVENT、AFTER_START_EVENT、BEFORE_STOP_EVENT、STOP_EVENT、AFTER_STOP_EVENT 。当组件启动时,正常会触发前3个事件,而关闭组件时,会触发后3个事件。如果Catalina组件可以触发事件,那么需要编写相应的事件监听器对这些事件进行响应。事件监听器是org.apache.catalina.LifecycleListener接口实例。
tomcat内部架构各个核心组件的包含关系。例如server包含service,service包含container,一层层包含。而这种结构类似数据结构中的树形结构,对于tomcat的启动也是鉴于此,可以通过父容器启动子容器,这样可以达到只要启动根容器,从而启动所有的组件,同时便于管理达到统一启动、停止、关闭的效果。
生命周期采用是观察者模式(监听事件)。
简单看一下tomcat的设计源码
事件对象LifecycleEvent
public final class LifecycleEvent extends EventObject { private static final long serialVersionUID = 1L; // ----------------------------------------------------------- Constructors /**
* Construct a new LifecycleEvent with the specified parameters.
*
* @param lifecycle Component on which this event occurred
* @param type Event type (required)
* @param data Event data (if any)
*/
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) { super(lifecycle);
this.type = type;
this.data = data;
} // ----------------------------------------------------- Instance Variables /**
* The event data associated with this event.
*/
private Object data = null; /**
* The event type this instance represents.
*/
private String type = null; // ------------------------------------------------------------- Properties /**
* Return the event data of this event.
*/
public Object getData() { return (this.data); } /**
* Return the Lifecycle on which this event occurred.
*/
public Lifecycle getLifecycle() { return (Lifecycle) getSource(); } /**
* Return the event type of this event.
*/
public String getType() { return (this.type); } }
事件监听接口LifecycleListener
public interface LifecycleListener { /**
* Acknowledge the occurrence of the specified event.
*
* @param event LifecycleEvent that has occurred
*/
public void lifecycleEvent(LifecycleEvent event); }
事件监听实现类JasperListener
public void lifecycleEvent(LifecycleEvent event) { if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
try {
// Set JSP factory
Class.forName("org.apache.jasper.compiler.JspRuntimeContext",
true,
this.getClass().getClassLoader());
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
// Should not occur, obviously
log.warn("Couldn't initialize Jasper", t);
}
// Another possibility is to do directly:
// JspFactory.setDefaultFactory(new JspFactoryImpl());
} }
事件监听类LifecycleSupport
public void addLifecycleListener(LifecycleListener listener) { synchronized (listenersLock) {
LifecycleListener results[] =
new LifecycleListener[listeners.length + 1];
for (int i = 0; i < listeners.length; i++)
results[i] = listeners[i];
results[listeners.length] = listener;
listeners = results;
} }
//触发事件
public void fireLifecycleEvent(String type, Object data) { LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = listeners;
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event); }
//移除事件
public void removeLifecycleListener(LifecycleListener listener) { synchronized (listenersLock) {
int n = -1;
for (int i = 0; i < listeners.length; i++) {
if (listeners[i] == listener) {
n = i;
break;
}
}
if (n < 0)
return;
LifecycleListener results[] =
new LifecycleListener[listeners.length - 1];
int j = 0;
for (int i = 0; i < listeners.length; i++) {
if (i != n)
results[j++] = listeners[i];
}
listeners = results;
} }
事件源 ServerStandard@startInternal()
//触发事件
protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING); globalNamingResources.start(); // Start our defined Services
synchronized (services) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
下面写了一个简单观察者模式的例子,便于理解。
import java.util.ArrayList;
import java.util.List; class MacBookPro{ public List<ITClient> clients = new ArrayList<ITClient>(); public void addClientListener(ITClient client){
clients.add(client);
}
public void notifyClient(String info){
//通知所有放入监听者
clients.forEach(x->x.receiveInfo(info));
}
}
class ITClient{ private String name; public ITClient(String name)
{
this.name = name;
}
public void receiveInfo(String info){
System.out.println(this.name+" :: "+info);
}
}
public class StateTest
{
public static void main(String[] args)
{
MacBookPro mbp = new MacBookPro();
ITClient c1 = new ITClient("员工1");
ITClient c2 = new ITClient("员工2");
ITClient c3 = new ITClient("员工3");
mbp.addClientListener(c1);
mbp.addClientListener(c2);
mbp.addClientListener(c3);
System.out.println("促销活动开始了");
mbp.notifyClient("京东618大减价");
}
}
结果:
促销活动开始了
员工1 :: 京东618大减价
员工2 :: 京东618大减价
员工3 :: 京东618大减价
最新文章
- 让view 覆盖导航栏
- 医失眠灵验方--五味子50g 茯神50g 合欢花15g 法半夏15g
- ios import和@class的区别
- mysql的二级索引
- 【转】C/C++中的日期和时间 TIME_T与STRUCT TM转换&mdash;&mdash;2013-08-25 16
- 突然兴起复习一下Swift3.0
- Linux的rsync 配置,用于服务器之间远程传大量的数据
- Unity 3D游戏开发学习路线(方法篇)
- Python爬虫入门教程 10-100 图虫网多线程爬取
- streamsets
- 从零开始学安全(二十二)●PHP日期date参数表
- 获取邮箱的DNS和MX 工具类
- mocha测试框架-truffle
- 性能测试二十七:环境部署之Dubbo原理
- Python3基础 dict fromkeys 多个键对应相同的值
- 《Javascript权威指南-第6版》
- 有了Auto Layout,为什么你还是害怕写UITabelView的自适应布局?
- css border
- PlantUML —— 应用于 Eclipse 的简单快速的 UML 编辑软件
- win 7 下vim的使用