tomcat 7 启动时 先 启动catalina ,利用 digester 工具包来解析server.xml 创建 server ;
server 包含 service
service 包含 container 和 Connector ;
container 的体系从高到低 依次为 engine > host >context>wrapper。
server 启动 service代码如下:
@Override
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();
}
}
}
(这里为什么要同步呢? 看起来启动server 是在main线程进行的。)
依次启动service ,service启动代码如下:
@Override
protected void startInternal() throws LifecycleException {
if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING);
// Start our defined Container first
if (container != null) {
synchronized (container) {
container.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
// Start our defined Connectors second
synchronized (connectors) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
先启动的是container:
container 体系如下 :
container 容器有4中实现,级别从高到低为 engine >host >context >wapper。所有的 容器均继承 containerBase 。
containerbase 包含一个 pipeline 和 startStopExecutor 任务执行器 ;
每个容器调用containerbase 的方法启动,containerbase 启动代码如下:
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<Future<Void>>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
results.add(startStopExecutor.submit(new StartChild(children[i])));
这里用到了 threadpoolExcuter 封装的线程池,封装成任务执行器;把每一个注册的子容器提交给一个任务执行器来启动
private static class StartChild implements Callable<Void> {
private Container child;
public StartChild(Container child) {
this.child = child;
}
@Override
public Void call() throws LifecycleException {
child.start();
return null;
}
}
每一个 startChild 线程启动一个container,这是递归调用的,子容器又会启动子容器,最底层的容器最先启动完成。
然后等待直到每一个子容器启动完成:
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
子容器全部启动完成之后,启动 pipeline
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
containerbase 持有一个standardPipeline,pipeline 也持有自己所在容器的引用
/**
* The Pipeline object with which this Container is associated.
*/
protected Pipeline pipeline = new StandardPipeline(this);
pipeline启动代码如下:pipeline会先启动server.xml自定义的Valve ,最后启动 basic Valve。
@Override
protected synchronized void startInternal() throws LifecycleException {
// Start the Valves in our pipeline (including the basic), if any
Valve current = first;
if (current == null) {
current = basic;
}
while (current != null) {
if (current instanceof Lifecycle)
((Lifecycle) current).start();
current = current.getNext();
}
setState(LifecycleState.STARTING);
}
basic Valve 是容器初始化时绑定给pipeline的:
standardEngine 的初始化代码如下:
/**
* Create a new StandardEngine component with the default basic Valve.
*/
public StandardEngine() {
super();
pipeline.setBasic(new StandardEngineValve());
/* Set the jmvRoute using the system property jvmRoute */
try {
setJvmRoute(System.getProperty("jvmRoute"));
} catch(Exception ex) {
log.warn(sm.getString("standardEngine.jvmRouteFail"));
}
// By default, the engine will hold the reloading thread
backgroundProcessorDelay = 10;
}
可见,engine 容器的 pipeline绑定的 basic Valve 就是 StandardEngineValve 。
StandardEngineValve 就是一个实例,不包含任何别的组件了,因此Valve 的start() 只是设置一个启动状态,然后什么也不做。
当创建各级容器实例的时候,(创建容器实例在 Catalina 启动Server 之前就完成了。)
1. StandardHost 给子容器 context 绑定了一个监听器。
/**
* Add a child Container, only if the proposed child is an implementation
* of Context.
*
* @param child Child container to be added
*/
@Override
public void addChild(Container child) {
child.addLifecycleListener(new MemoryLeakTrackingListener());
if (!(child instanceof Context))
throw new IllegalArgumentException
(sm.getString("standardHost.notContext"));
super.addChild(child);
}
这个监听器当context启动完成之后,把context 的 classLoader 绑定到host 。记录内存泄漏用。。(控制台用的。。)
2. Engine
在Catalina 创建默认的StandardEngine 时,同时也将自己的classLoader 传递给了 StandardEngine, 也就是CommonClassLoader。
3. Contetxt
当使用Digetser创建 Context 时, Context 会创建一个 WabAppLoader 的实例,这个loader 是支持热部署的。
当 Digester 实例化 Context 之后, 还会调用 Context 的 setLoader() 方法,这个方法里启动了WebAppLoader ,调用 它的StartInternal() 方法。
// Construct a class loader based on our current repositories list
try {
classLoader = createClassLoader();
classLoader.setResources(container.getResources());
classLoader.setDelegate(this.delegate);
classLoader.setSearchExternalFirst(searchExternalFirst);
if (container instanceof StandardContext) {
classLoader.setAntiJARLocking(
((StandardContext) container).getAntiJARLocking());
classLoader.setClearReferencesStatic(
((StandardContext) container).getClearReferencesStatic());
classLoader.setClearReferencesStopThreads(
((StandardContext) container).getClearReferencesStopThreads());
classLoader.setClearReferencesStopTimerThreads(
((StandardContext) container).getClearReferencesStopTimerThreads());
classLoader.setClearReferencesHttpClientKeepAliveThread(
((StandardContext) container).getClearReferencesHttpClientKeepAliveThread());
}
for (int i = 0; i < repositories.length; i++) {
classLoader.addRepository(repositories[i]);
}
// Configure our repositories
setRepositories();
setClassPath();
setPermissions();
((Lifecycle) classLoader).start();
首先创建一个WebAppClassLoader ,这个才是 WebappLoader 这个组件持有的真正的类加载器。
这里那么它的父类加载器是谁呢? 想想上面提到的 Engine 容器的设置的 classLoader ,就是这个Catalina 传递的 CommomClassLoader了。
if (parentClassLoader == null) {
parentClassLoader = container.getParentClassLoader();
}
CommomClassLoader 加载所有Server 都能访问的类库一个 WebappClassLoader 加载一个 webapp
server 是在main 线程运行的,service 也是在main 线程运行的,(待续)