本文章仅作为了解tomcat的基础不做深入研究,文章来源:《看透Spring MVC源代码分析与实践》韩璐彪 著
GitHub地址
Tomcat中最顶层的容器叫Server,代表整个服务器;
Server中至少包含一个Service
Service用于提供具体服务:Service主要包含两部分:
Connector和Container。
Tomcat中的Server由org.apache.catalina.startup.Catalina来操作,Catalina是整个Tomcat的管理类,他里面的三个方法load、start、stop就是分别用来加载、启动、停止整个服务器,
通过研读该方法可以发现该方法调用了Server中的start,而Server的start又调用了Service的start,只不过是Catalina调用了Server一次start方法,而Server调用了每一个Service的start方法,load与stop均是如此,
代码连接
Tomcat的入口main(Java写的嘛,自然是通过main方法启动)并不在Catalina类中,正式启动是在org.apache.catalina.startup.Bootstrap中。这个类作用是转化Catalina的实例并调用相应的方法(Bootstrap与Catalina的关系像是一种代理关系),创建了实例后通过脚本catalina.bat/catalina.sh
传递过来的参数进行相应配置并调用load、start、stop方法根据代码可知,start与load会受到参数影响,而stop不会也没必要
注意:该类中包含比较多的静态代码建议多读一读
代码连接
作为正式的服务器启动器,该类有三个主要方法setAwait、load和start方法,setAwait方法用于设置Server启动完成后是否进入等待状态的标志,这个可以通过配置完成设置,由上面的Bootstrap中的main方法反射并固定为true,Bootstrap的main方法主要调用setAwait如下
Bootstrap bootstrap = new Bootstrap();
···
daemon = bootstrap;
···
else if (command.equals("start")) {
daemon.setAwait(true);//本行***
daemon.load(args);
daemon.start();
if (null == daemon.getServer()) {
System.exit(1);
}
}
···
public void setAwait(boolean await)
throws Exception {
Class> paramTypes[] = new Class[1];
paramTypes[0] = Boolean.TYPE;
Object paramValues[] = new Object[1];
paramValues[0] = Boolean.valueOf(await);
Method method =
catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
method.invoke(catalinaDaemon, paramValues);
}
load方法与start不做赘述,看代码比较好比较复杂,反射用了很多,总的来说这两个方法的主要作用如下:
代码链接
从前面讲述结构时已经表述,一个Server下存在多个Service,为了方便操作Server,Server类中提供了addService、removeService方法来添加和删除Service,并且Server的init方法和start方法分别循环调用了每个Service的init方法和start方法来启动所有的Service
Server的默认实现是org.apache.catalina.core.StandardServer
继承关系为: StandardServer<-LifecycleMBeanBase-
init和start方法就在LifecycleBase,并且该类提供了initInternal方法和startInternal方法作为模板方法,由子类具体实现,这两个方法与Tomcat的生命周期管理有关,在此不做陈述,我会单独发一篇说明Tomcat的生命周期的管理方式的文章
代码链接
Service的默认实现是org.apache.catalina.core.StandardService,
继承关系为: StandardService<-LifecycleMBeanBase-
让我们看一下init和start的模板方法:
//强烈建议读源码,理解较为深刻
//init模板方法
protected void initInternal() throws LifecycleException {
super.initInternal();
if (engine != null) {
engine.init();
}
// Initialize any Executors
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
executor.init();
}
// Initialize mapper listener
mapperListener.init();
// Initialize our defined Connectors
synchronized (connectorsLock) {
for (Connector connector : connectors) {
connector.init();
}
}
}
//start模板方法
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 (engine != null) {
synchronized (engine) {
engine.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
}
mapperListener.start();
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
}
}
}
可以看出StandardService中的initInternal和starInternal主要调用了container、executor、mapperListener以及connectors的init和start方法,其中mapperListener是用来箭筒container容器变化的,executors使用在connectors中管理线程的线程池,具体用法参考conf/server.xml,搜索关键字Executor Connector,该配置文件中大量用法都被注释起来了,有兴趣可以研究下
当所有的Service运行完start方法,那么整个tomcat就启动了,接下来就可以通过项目访问地址访问web项目了。