一个完整的Web容器是由许多组件组成的,在容器启动时,这些组件必须全部要启动,并且初始化,当容器停止时,它们也要清除。(例如servlet要调用destory方法)保持组件启动和停止一致的机制就是通过LifeCycle接口来实现的。
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
LifeCycle接口定义了这六个事件,根据字面意思可以看出,前三个是组件启动时发生的事件,后面三个是组件停止时发生的事件。LifeCycle接口中最重要的是start与stop方法,实现了这两个方法的组建类就可以被父组建启动和停止了,另外3个方法addLifecycleListener(),findLifecycleListeners(),和removeLifecycleListener()这三个方法和监听器相关,组件中可以具有对在该组件发生的事件感兴趣的监听器。当事件发生时,将会通知对该事件感兴趣的监听器。
那么组件的生命周期如何实现呢?我们具体来跟一下这个流程吧。
public synchronized void start() throws LifecycleException {
if (started)
throw new LifecycleException("SimpleContext has already started");
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
started = true;
try {
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
// Start our child containers, if any
Container children[] = findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Lifecycle)
((Lifecycle) children[i]).start();
}
// Start the Valves in our pipeline (including the basic),
// if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
// Notify our interested LifecycleListeners
lifecycle.fireLifecycleEvent(START_EVENT, null);
}
catch (Exception e) {
e.printStackTrace();
}
这是实现了Lifecycle接口的context类的start方法,首先LifecycleSupport类的实例lifecycle实例调用了fireLifecycleEvent方法,与“before-start-event”相关的事件就会发生,然后启动loader,启动所有组件,随后拿到所有的子容器,把他们都启动,再然后启动管道,激活所有的阀门,在调用了fireLifecycleEvent方法后,start方法也就结束了,至此,容器启动成功。
public void lifecycleEvent(LifecycleEvent event) {
Lifecycle lifecycle = event.getLifecycle();
System.out.println("SimpleContextLifecycleListener's event " +
event.getType().toString());
if (Lifecycle.START_EVENT.equals(event.getType())) {
System.out.println("Starting context.");
}
else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
System.out.println("Stopping context.");
}
}
这是监听器实现的lifecycleEvent方法。
public final class Bootstrap {
public static void main(String[] args) {
Wrapper wrapper1 = new SimpleWrapper();
wrapper1.setName("Primitive");
wrapper1.setServletClass("PrimitiveServlet");
Wrapper wrapper2 = new SimpleWrapper();
wrapper2.setName("Modern");
wrapper2.setServletClass("ModernServlet");
Context context = new SimpleContext();
context.addChild(wrapper1);
context.addChild(wrapper2);
Mapper mapper = new SimpleContextMapper();
mapper.setProtocol("http");
context.addMapper(mapper);
LifecycleListener listener = new SimpleContextLifecycleListener();
((Lifecycle) context).addLifecycleListener(listener);
Loader loader = new SimpleLoader();
context.setLoader(loader);
// context.addServletMapping(pattern, name);
context.addServletMapping("/Primitive", "Primitive");
context.addServletMapping("/Modern", "Modern");
Connector connector = new HttpConnector();
connector.setContainer(context);
try {
connector.initialize();
((Lifecycle) connector).start();
((Lifecycle) context).start();
// make the application wait until we press a key.
System.in.read();
((Lifecycle) context).stop();
}catch (Exception e) {
e.printStackTrace();
}
}
}
最后来温习一下整个流程吧:
- 首先构建两个Wrapper,把servlet的签名与class信息set进去
- 然后创建上下文(Context),把上面创建的两个包装器加为子容器
- 随后构建一个mapper,设置好协议,再加入到容器中
- 往容器中添加监听器
- 给servlet加上映射路径
- 构建HttpConnector,并把容器添加进去
- 初始化连接器,启动连接器,启动容器
- 停止容器