一、tomcat的启动核心流程
前面给大家介绍了tomcat中的生命周期的设计,掌握了这块对于我们分析tomcat的核心流程是非常有帮助的,也就是我们需要创建相关的核心组件,比如server,service肯定都绕不开生命周期的方法。

1.启动的入口
你可以通过脚本来启动tomcat服务(startup.bat),但如果你看过脚本的命令,你会发现最终调用的还是bootstrap中的main方法,所以我们需要从main方法来开始

然后我们去看main方法中的代码,我们需要重点关注的方法有三个
- bootstrap.init()方法
- load()方法
- start()方法
也就是在这三个方法中会完成tomcat的核心操作。
2.init方法
我们来看下init方法中的代码,非核心的我们直接去掉
public void init() throws exception {
// 创建相关的类加载器
initclassloaders();
// 省略部分代码...
// 通过反射创建了 catalina 类对象
class<?> startupclass = catalinaloader
.loadclass("org.apache.catalina.startup.catalina");
// 创建了 catalina 实例
object startupinstance = startupclass.getconstructor().newinstance();
// 省略部分代码...
string methodname = "setparentclassloader";
class<?> paramtypes[] = new class[1];
paramtypes[0] = class.forname("java.lang.classloader");
object paramvalues[] = new object[1];
paramvalues[0] = sharedloader;
// 把 sharedloader 设置为了 commonloader的父加载器
method method =
startupinstance.getclass().getmethod(methodname, paramtypes);
method.invoke(startupinstance, paramvalues);
// catalina 实例 赋值给了 catalinadaemon
catalinadaemon = startupinstance;
}
- 首先是调用了initclassloaders()方法,这个方法会完成对应的classloader的创建,这个比较重要,后面专门写一篇文章来介绍。
- 通过反射的方式创建了catalina的类对象,并通过反射创建了catalina的实例
- 设置了类加载器的父子关系
- 用过成员变量catalinadaemon记录了我们创建的catalina实例
这个是通过bootstrap.init()方法我们可以获取到的有用的信息。然后我们继续往下面看。
3.load方法
然后我们来看下load方法做了什么事情,代码如下:
private void load(string[] arguments) throws exception {
// call the load() method
string methodname = "load"; // 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;
}
// catalinadaemon 就是在 init中创建的 catalina 对象
method method =
catalinadaemon.getclass().getmethod(methodname, paramtypes);
if (log.isdebugenabled()) {
log.debug("calling startup class " + method);
}
// 会执行 catalina的load方法
method.invoke(catalinadaemon, param);
}
上面的代码非常简单,通过注释我们也可以看出该方法的作用是调用 catalina的load方法。所以我们还需要加入到catalina的load方法中来查看,代码同样比较长,只留下关键代码
public void load() {
if (loaded) {
return; // 只能被加载一次
}
loaded = true;
initdirs(); // 废弃的方法
// before digester - it may be needed
initnaming(); // 和jndi 相关的内容 忽略
// create and execute our digester
// 创建并且执行我们的 digester 对象 server.xml
digester digester = createstartdigester();
// 省略掉了 digester文件处理的代码
getserver().setcatalina(this); // server对象绑定 catalina对象
getserver().setcatalinahome(bootstrap.getcatalinahomefile());
getserver().setcatalinabase(bootstrap.getcatalinabasefile());
// stream redirection
initstreams();
// 省略掉了部分代码...
getserver().init(); // 完成 server service engine connector等组件的init操作
}
把上面的代码简化后我们发现这个load方法其实也是蛮简单的,就做了两件事。
- 通过apache下的digester组件完成了server.xml文件的解析
- 通过getserver().init() 方法完成了server,service,engin,connector等核心组件的初始化操作,这块和前面的lifecyclebase呼应起来了。

如果生命周期的内容不清楚,请看前面内容介绍
4.start方法
最后我们来看下start方法的代码。
public void start() throws exception {
if (catalinadaemon == null) {
init(); // 如果 catalinadaemon 为空 初始化操作
}
// 获取的是 catalina 中的 start方法
method method = catalinadaemon.getclass().getmethod("start", (class [])null);
// 执行 catalina 的start方法
method.invoke(catalinadaemon, (object [])null);
}
上面的代码逻辑也很清楚,就是通过反射的方式调用了catalina对象的start方法。所以进入catalina的start方法中查看。
public void start() {
if (getserver() == null) {
load(); // 如果server 为空 重新 init 相关的组件
}
if (getserver() == null) {
log.fatal("cannot start server. server instance is not configured.");
return;
}
// start the new server 关键方法--->启动server
try {
getserver().start();
} catch (lifecycleexception e) {
// 省略...
}
// 省略...
// register shutdown hook 注册关闭的钩子
if (useshutdownhook) {
// 省略...
}
if (await) {
await();
stop();
}
}
通过上面的代码我们可以发现核心的代码还是getserver.start()方法,也就是通过server对象来嵌套的调用相关注解的start方法。

5.核心流程的总结
我们可以通过下图来总结下tomcat启动的核心流程

从图中我们可以看到bootstrap其实没有做什么核心的事情,主要还是catalina来完成的。
以上就是tomcat启动核心流程示例详解的详细内容,更多关于tomcat启动流程的资料请关注代码网其它相关文章!
发表评论