文章目录
- 叨叨
- 程序入口
- 加载load
- 流程简述
- Bootstrap.load()
- Catalina.load(params)
- init()模板方法
- init流程总结
- start()模板方法
- 流程简述
- start()模板方法
- Host.start()特别说明
叨叨
讲真,最开始源码调试几遍下来还是很懵了,尤其是组件初始化过程中不断去调用其他组件的init()方法,中间使用模板方法的设计模式,最终抽象方法交给哪个子类去实现有点绕。这个搞明白之后,start()方法的流程就和init()类似了。过程中涉及的组件经过初步梳理,再结合server.xml中的标签,基本可以猜个七七八八,最后结合Tomcat的架构设计图进行梳理修正。
这里先记录下启动流程的学习。Tomcat源码的下载及相关配置就不赘述了,网上有很多教程。
程序入口
java程序的执行入口是main()方法,根据官网的启动流程描述或者启动脚本中的内容,可以定位到一个类:
org.apache.catalina.startup.Bootstrap

进到这个类中直接搜索main()方法,看下main()方法主要分为两大块:
- 初始化bootstrap
进入init()方法可以看到是在做类加载器的初始化与设置- 加载与启动bootstrap
条件判断进入load()和start()的执行,按照猜想,在设置完类加载器后,框架启动的尿性就是读取并加载配置,初始化核心组件对象,然后启动框架。下面着重看下load和start两个方法。

加载load
流程简述
加载什么呢?无非就是:
- 配置信息的加载(毕竟我们还有个配置文件server.xml)
- 核心对象的加载
看下源码究竟做了什么:
Bootstrap.load()
通过反射调用Catalina.load()
Method method =catalinaDaemon.getClass().getMethod("load", paramTypes);
if (log.isDebugEnabled())log.debug("Calling startup class " + method);
System.out.println("******************* >>> 反射调用Catalina.load()");
method.invoke(catalinaDaemon, param);
Catalina.load(params)
首次看到load方法,直观感受:
- 有几个init开头的方法,初始化可能会用到的资源
- 创建了一个Digester对象,并解析输入源 digester.parse(inputSource)
- 执行getServer().init()
// inputSource来自于一个文件
digester.parse(inputSource);
// 文件正是 configFile = "conf/server.xml";
file = configFile();
所以digester对象是用来解析server.xml的。
getServer()返回一个Server对象,server何时被set进Catalina对象中的?
最后调用server.init()开始初始化流程。
init()模板方法
init()方法是接口Lifecycle中的方法,可以看到init()方法在LifecycleBase类中实现,该类是一个抽象类,并且在init()方法的执行逻辑中调用抽象方法initInternal(),这不是妥妥的模板方法设计模式么。
所以这个initInternal应该是在某个server实现类A中执行的,且类A需要继承LifecycleBase或其子类。server只有一个实现类StandardServer且满足上述条件。
LifecycleBase中init模板方法:

StandardServer中的实现:
// The set of Services associated with this Server.
private Service services[] = new Service[0];protected void initInternal() throws LifecycleException {// 调用父类super.initInternal();//...// Initialize our defined Servicesfor (int i = 0; i < services.length; i++) {services[i].init();}//...
}
super.initInternal()方法:

最开始看到这里时还是有点乱的,梳理之后就发现这样的层次逻辑很清晰。通常我们使用模板方法> 有两层:
第一层:抽象模板类
第二层:继承了抽象类的具体子类Tomcat这里你可以理解成有三层:
第一层:抽象模板类
第二层:继承了抽象类的通用基础类LifecycleMBeanBase
第三层:继承了基础类的具体子类StandardXXX类模板类中定义了模板方法init和抽象方法initInternal;基础类中实现initInternal时做了公共逻辑的抽> 取(即注册组件),最后在具体组件类中进行具体组件的初始化逻辑。
看一下类的继承关系:

再看一下在service组件的initInternal方法中,调用了engine,executor,mapperListener,connector四个组件的init()方法:
在具体组件类的初始化过程initInternal()中,都是通过super.initInternal()调用通用的组件注册逻
辑,最后再执行组件自身的初始化逻辑。
service中四个组件的init概览:
engine.init();1. Host组件的初始化并没有在此处执行,而是在start阶段进行的。(具体见start过程)2. engine的初始化主要做了如下操作:3. realm对象的处理4. 完成engine组件的注册executor.init();完成executor组件的注册mapperListener.init();完成listener组件的注册connector.init();1. 创建coyote适配器2. protocolHandler.init() --> abstractProtocol.init() --> endpoint.init()
init流程总结
两load:
bootstrap.load:反射调用Catalina.load();
catalina.load:创建xml解析器解析server.xml配置,调用server.init()开始初始化;
Lifecycle实现类与模板方法模式:
通过定义Lifecycle接口以及使用模板方法,规范并统一了组件类的初始化过程。
需要注意:
Host等组件的初始化是在start过程中进行的。(见下说明)
start()模板方法
流程简述
组件的start()方法与init的流程类似,也是通过Lifecycle接口配合使用模板方法的模式完成组件的启动。
boostrap.start通过反射调用Catalina.start()
Catalina.start
- 检查server实例是否存在
- getServer().start()启动server
start()模板方法
LifecycleBase中start模板方法:
public final synchronized void start() throws LifecycleException {System.out.println("******************* >>> "+this.getClass().getName()+" 调用LifecycleBase.start");if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||LifecycleState.STARTED.equals(state)) {if (log.isDebugEnabled()) {Exception e = new LifecycleException();log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);} else if (log.isInfoEnabled()) {log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));}return;}// 检查组件状态,是否需要初始化。Host等主键的初始化就是在这里开始的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)) {// This is a 'controlled' failure. The component put itself into the// FAILED state so call stop() to complete the clean-up.stop();} else if (!state.equals(LifecycleState.STARTING)) {// Shouldn't be necessary but acts as a check that sub-classes are// doing what they are supposed to.invalidTransition(Lifecycle.AFTER_START_EVENT);} else {setStateInternal(LifecycleState.STARTED, null, false);}} catch (Throwable t) {// This is an 'uncontrolled' failure so put the component into the// FAILED state and throw an exception.ExceptionUtils.handleThrowable(t);setStateInternal(LifecycleState.FAILED, null, false);throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t);}
}protected abstract void startInternal() throws LifecycleException;
StandardServer中的实现:
protected void startInternal() throws LifecycleException {fireLifecycleEvent(CONFIGURE_START_EVENT, null);setState(LifecycleState.STARTING);globalNamingResources.start();// Start our defined Servicessynchronized (servicesLock) {for (int i = 0; i < services.length; i++) {services[i].start();}}
}
service的start():
与init过程类似,在start过程中,同样也是同时对多个组件进行start()方法调用。
StandardEngine.start
直接调用父类ContainerBase.startInternal()方法,启动子组件和子容器;
子容器组件的启动通过线程池
StandardContext.startInternal
Host.start()特别说明
按照上面几个组件的加载机制以及server.xml中标签的层次结构,engine初始化时应该调用host的初始化方法,网上很多教程帖子的启动时序图也都是那样画的。这跟源码中的init流程是不符的


于是我开始在load阶段逐行阅读,始终找不到哪里调用了Host的init方法,最后在日志中找到答案:

启动流程之后细说,这里只需要知道:
- engine会将子标签(server.xml标签层级)对象遍历出来构建成可运行的线程丢到线程
- 这些子标签组件会调用自身的start()方法启动
- 组件启动时会检查组件状态,如果为NEW则会执行组件init方法




















