背景
本来打算写一期介绍tomcat如何打破双亲委派模型的文章,结果发现补充的前置知识有点多,干脆单独成一篇文章好了;后面如果有其他前置知识或者是发现tomcat设计的有趣的地方继续在这里更新 又水一期博客捏
关于双亲委派模型的介绍可以查看JavaGuide
关于如何对tomcat进行debug,由于tomcat是用ant构建的,本机断点debug比较折腾;所以可以使用嵌入版Tomcat构建一个简单的web项目更方便的进行调试。实例
所谓嵌入版Tomcat其实就是SpringBoot锁使用的内嵌http服务器+servlet容器;可以作为一项依赖加入项目中从而在代码中控制Tomcat的启停。
Tomcat相关前置知识
为什么要打破双亲委派?
因为tomcat可以同时运行多个web应用,可能两个应用中都有一个全名为com.ali.dao.User
的类,但是他们的内容是不同的,tomcat如果使用传统的双亲委派就一定会导致两个类混掉从而有一个项目不能正常运行。
tomcat 组件
tomca组件生命周期管理
tomcat为所有组件的生命周期抽象出了一个接口Lifecycle
关于组件的生命周期相关方法的通用接口。catalina组件可能会实现这个接口(以及他们支持的功能的适当接口)从而提供组件启动和停止的统一机制。
合法的组件状态转移图:
任一状态都可转换为FAILED。
略去一些特殊规定……
在状态变化期间发送 LifecycleEvents
的逻辑是在触发更改的方法中定义的。
不合法的状态转换不会发出Events
观察者模式
既然涉及到了Events那么一定用到了观察者设计模式
这个观察者模式实现的很经典~
- Listener接口,需要订阅事件的组件自行实现这个接口
public interface LifecycleListener {
//定义收到事件后的动作
public void lifecycleEvent(LifecycleEvent event);
}
- 在
LifecycleBase
类中维护了一个List<LifecycleListener> lifecycleListeners
,用于注册事件接收者(各组件启动时会注册自己)
- 在
LifecycleBase
中定义了一个带默认实现的fireLifecycleEvent()
方法,子类都是调用它来‘发送’事件;
但事件并没有真的被‘发送’到哪里,只是会用这个事件通知所有liftcycleListeners中的订阅者,让他们执行相应动作。
protected void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(this, type, data);
//通知所有订阅者;无论是什么事件都会通知所有订阅者,由订阅者自行判断是否处理该事件
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
源码调试
tomcat启动
最开始几天没有什么抓手,所以就从Tomcat的启动开始读源码(是的,又忘记断点调试这个东西了);读了几天收获不大,主要是对生命周期的实现更了解了一些;
这里以StanderServer的启动为例,其他组件大致相同:
- NEW->STARTING_PREP
这一步由LifecycleBase
抽象类的start()方法实现,作为final方法其子类也无权重写
这个方法主要职责是控制状态转换并调用子类重写的startInternal()方法
LifecycleBase.start()
@Override
//synchronized 防止并发问题
public final synchronized void start() throws LifecycleException {
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
//防止重复启动
return;
}
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
//这个方法由子类重写,是真正进行启动逻辑的地方
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// 可控的失败. 自发将状态转换为失败从而调用stop()方法进行善后
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// 冗余, 只是检查子类有没有正确的实现internal方法
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
// 这里是不可控的失败,所以更改状态到FAILED并抛出异常
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);
}
}
- STARTING_PREP->STARTING
在子类的startInternal()方法一开始进行转换,代表开始进行启动逻辑
在这里会进行类似DFS的操作对子容器进行启动(部分异步)
ContainerBase.startInternal()
@Override
protected synchronized void startInternal() throws LifecycleException {
//检测关联组件是否启动
Cluster cluster = getClusterInternal();
if (cluster instanceof Lifecycle) {
((Lifecycle) cluster).start();
}
Realm realm = getRealmInternal();
if (realm instanceof Lifecycle) {
((Lifecycle) realm).start();
}
// 异步启动子组件
Container children[] = findChildren();
List> results = new ArrayList<>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
MultiThrowable multiThrowable = null;
//检查子组件是否启动成功
for (Future result : results) {
try {
result.get();
} catch (Throwable e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
if (multiThrowable == null) {
multiThrowable = new MultiThrowable();
}
multiThrowable.add(e);
}
}
//子组件启动异常,抛出
if (multiThrowable != null) {
throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
multiThrowable.getThrowable());
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle) {
((Lifecycle) pipeline).start();
}
setState(LifecycleState.STARTING);
// Start our thread
threadStart();
}