tomcat源码系列导航栏
tomcat启动过程-load初始化
目录
本篇文章主要是tomcat源码的load初始化流程,如果不知道tomcat源码如何启动请参考上一篇文章
启动入口Main函数
源码的启动函数在org.apache.catalina.startup.Bootstrap 中,以下是源代码。
public static void main(String args[]) {
Thread thread = Thread.currentThread();
synchronized (daemonLock) {
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
// When running as a service the call to stop will be on a new
// thread so make sure the correct class loader is used to
// prevent a range of class not found exceptions.
thread.setContextClassLoader(daemon.catalinaLoader);
}
}
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
......
if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
}
} catch (Throwable t) {
......
}
}
为了代码看上去更加清晰明了,用省略号省去了部分和本次启动流程不相关的代码。后面的文章会讲到省去的代码的作用。
启动main函数后默认command = "start" ,接下来执行daemon.load(args)。请看代码块一
代码块一 load方法
private void load(String[] arguments) throws Exception {
// Call the load() method
String methodName = "load";
Object param[];
Class<?> paramTypes[];
if (arguments==null || arguments.length==0) {
paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled()) {
log.debug("Calling startup class " + method);
}
method.invoke(catalinaDaemon, param);
}
可以看到这里使用了反射的技术执行了org.apache.catalina.startup.Catalina这个类的load方法。这里是使用之前创建好的对象来进行反射获取对象的方法来执行。为什么不直接通过对象调用方法来执行呢。应该是考虑到代码的可扩展型吧。接下来再看Catalina的load方法,代码块二
代码块二 load方法
/**
* Start a new server instance.
*/
public void load() {
if (loaded) {
return;
}
loaded = true;
//解析一 server.xml文件,将文件中的信息,比如根据类的全路径名称反射成对象然后将对象设置当this中去
Digester digester = createStartDigester();
......
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// Stream redirection
initStreams();
// Start the new server
try {
//解析二 获取得到server对象然后调用其init方法
getServer().init();
}
......
}
可以看到以上解析一的代码其实就是读取conf/server.xml 文件将文件中的信息给创建成我们需要的对象信息。后面的文章中的许多对象都是从这里创建的,有兴趣的话可以自己去研究一下,他是怎么解析文件和然后创建对象的。
解析二获取的server对象就是解析一创建的,这里会调用server对象的init方法。请看 代码块三 init
代码块三 init
我们会发现init这个方法其实是org.apache.catalina.Lifecycle 接口的一个方法。以下是这个接口的代码
public interface Lifecycle {
// ----------------------------------------------------- Manifest Constants
//解析 一 以下是定义的一些生命周期事件名称
/**
* The LifecycleEvent type for the "component before init" event.
*/
public static final String BEFORE_INIT_EVENT = "before_init";
/**
* The LifecycleEvent type for the "component after init" event.
*/
public static final String AFTER_INIT_EVENT = "after_init";
/**
* The LifecycleEvent type for the "component start" event.
*/
public static final String START_EVENT = "start";
/**
* The LifecycleEvent type for the "component before start" event.
*/
public static final String BEFORE_START_EVENT = "before_start";
/**
* The LifecycleEvent type for the "component after start" event.
*/
public static final String AFTER_START_EVENT = "after_start";
/**
* The LifecycleEvent type for the "component stop" event.
*/
public static final String STOP_EVENT = "stop";
/**
* The LifecycleEvent type for the "component before stop" event.
*/
public static final String BEFORE_STOP_EVENT = "before_stop";
/**
* The LifecycleEvent type for the "component after stop" event.
*/
public static final String AFTER_STOP_EVENT = "after_stop";
/**
* The LifecycleEvent type for the "component after destroy" event.
*/
public static final String AFTER_DESTROY_EVENT = "after_destroy";
/**
* The LifecycleEvent type for the "component before destroy" event.
*/
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
/**
* The LifecycleEvent type for the "periodic" event.
*/
public static final String PERIODIC_EVENT = "periodic";
/**
* The LifecycleEvent type for the "configure_start" event. Used by those
* components that use a separate component to perform configuration and
* need to signal when configuration should be performed - usually after
* {@link #BEFORE_START_EVENT} and before {@link #START_EVENT}.
*/
public static final String CONFIGURE_START_EVENT = "configure_start";
/**
* The LifecycleEvent type for the "configure_stop" event. Used by those
* components that use a separate component to perform configuration and
* need to signal when de-configuration should be performed - usually after
* {@link #STOP_EVENT} and before {@link #AFTER_STOP_EVENT}.
*/
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
// --------------------------------------------------------- Public Methods
// 解析二 下面定义了一些生命周期方法。还有添加 查找 删除监听者的方法,以及获取当前生命周期状态的方法
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException;
public LifecycleState getState();
public String getStateName();
}
这个接口其实就是定义了整个tomcat生命周期的接口。从 init->start->stop->destroy 其实前两个init和start方法在main函数中就可以看见,当执行了init方法紧接着就执行了start。
这个时候我们再看server.init方法 做了什么见代码块四 init
代码块四 init
@Override
public final synchronized void init() throws LifecycleException {
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
//注册一个事件,说server正在进行初始化中
setStateInternal(LifecycleState.INITIALIZING, null, false);
//在本抽象类中这是一个抽象方法,具体的实现。需要去找调用对象所属类。
//这里是server对象调用的,他的全路径名称是org.apache.catalina.core.StandardServer
//解析一
initInternal();
//注册一个事件,说server初始化完成了
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
其实这个方法是在org.apache.catalina.util.LifecycleBase这个抽象类中实现的,其实tomcat源码作者对模板设计模式的使用,将公共的代码块部分全部抽离到抽象类中去实现。这样可以减少重复代码的开发。
这里的公共代码就是注册事件。在这里表示server正在进行初始化,然后通知我的监听者们,你们之前定义好,对server正在初始化这个动作有其他操作的。现在该去做了。这里其实是监听者模式的一种使用。在整个源码中其实模板设计模式和监听者模式随处可见。读者要想更快速提升读源码的能力,这是必备技能。
我们接着往下看解析一 代码块五 initInternal
代码块五 initInternal
protected void initInternal() throws LifecycleException {
super.initInternal();
......
// Initialize our defined Services
for (Service service : services) {
service.init();
}
}
可以发现接下来就是service对象的init方法初始化。经过我们一直往下走发现这个其实是一个初始化链 先是server,接着是service,再是connector和engine,connector再到protocolHandler,再到endpoint。然后整个初始化load流程结束。
整体load初始化流程
流程图如下
总结
在tomcat初始化流程中,使用了反射解耦,使用模板设计模式提取公共代码提升代码可阅读性和简洁性,大量使用监听者模式,做一些初始化相关的事情。整个tomcat的生命周期都是围绕生命周期接口。整个初始化过程是一个链路,一环扣一环。下一篇文章将介绍start启动流程,重点会有tomcat的nio处理请求。对线程池的创建和使用。