tomcat 各个组件初始化及启动流程
结合源码来探索启动的流程
通过上一章的目录结构和体系结构的研究,我们对tomcat有一个初步的认识
我们先找到入口函数。根据"startd"命令来推导
Bootstrap 下面的main方法就是入口函数
上面图片只截取了启动的时候两个方法一个初始化,一个是开始启动,在初始化之前的 init 方法是初始化一些环境参数。这里就没有详细说明。我们先看
if (command.equals("startd")) {
args[args.length - 1] = "start";
//先初始化一个必要的组件 如server connetor service
//这里的daemon 是就是 Bootstrap自己
daemon.load(args);
//开始加载Engine 下面相关东西,像Host Conetxt weapp
daemon.start();
}
我们再往下看Bootstrap 的 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;
}
// 反射获取catalina 的对象的 load
Method method =
catalinaDaemon.getClass().getMethod(methodName, paramTypes);
if (log.isDebugEnabled())
log.debug("Calling startup class " + method);
//利用反射去调用 catalina的load方法
method.invoke(catalinaDaemon, param);
}
然后下一步我们去CatalinaDaemon验证下是不是有一个无参的load方法。
果然有一个load方法(方法代码太多只截取重要的部分)
public void load() {
//创建一个xml解析器
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
//读取conf/server.xml文件
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail", file), e);
}
}
····· //这里的一些代码是保证读到server.xml文件的内容
try {
inputSource.setByteStream(inputStream);
digester.push(this);
//解析 配置文件流,对配置文件里面的配置进行初始化
digester.parse(inputSource);
} catch (SAXParseException spe) {
log.warn("Catalina.start using " + getConfigFile() + ": " +
spe.getMessage());
return;
} catch (Exception e) {
log.warn("Catalina.start using " + getConfigFile() + ": " , e);
return;
} finally {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
·············· 下面就是开始 Server的初始化了
// Start the new server
try {
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new java.lang.Error(e);
} else {
log.error("Catalina.start", e);
}
}
long t2 = System.nanoTime();
if(log.isInfoEnabled()) {
log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
}
}
我们跟到里面getServer().init();看看做了什么,进去之后发现到了"Lifecycle" 类的 init()方法 这是一个接口,这个接口有三个实现类
除了 LifecycleBase里面是有现实,其他两个类都没有实现,那就不用肯定是调用LifecycleBase的init方法了。
public final synchronized void init() throws LifecycleException {
//默认的实现
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
setStateInternal(LifecycleState.INITIALIZING, null, false);
try {
//争对所有的子类初始化,这个地方调用的是自己的抽象方法。
initInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.initFail",toString()), t);
}
setStateInternal(LifecycleState.INITIALIZED, null, false);
}
点开 LifecycleBase类的 initInternal()方法,发现也是有很多实现,其实到这里我们应该去看哪个实现类了,肯定是跟Server有关的。于是乎我们就找到了
StandardServer 这个类的initInternal() 方法
protected void initInternal() throws LifecycleException {
//调用父类的 方法
super.initInternal();
// Register global String cache
// Note although the cache is global, if there are multiple Servers
// present in the JVM (may happen when embedding) then the same cache
// will be registered under multiple names
onameStringCache = register(new StringCache(), "type=StringCache");
// Register the MBeanFactory
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
onameMBeanFactory = register(factory, "type=MBeanFactory");
// Register the naming resources
//结合之前的tomcat 体系结构图中来看 globalNamingResources资源文件组件进行初始化
globalNamingResources.init();
··············· 此处代码省略
//这个地方就验证了官网说的 Server下面有多个Service 这的调
//service 里面的init方法
// Initialize our defined Services 初始化多个services
for (int i = 0; i < services.length; i++) {
services[i].init();
}
}
这里Service 调用的init 方法是 Lifecycle的,
之前我们说Lifecycle init 是LifecycleBase实现了
我们看下LifecycleBase 的init 方法
public final synchronized void init() throws LifecycleException {
//默认的实现
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
setStateInternal(LifecycleState.INITIALIZING, null, false);
try {
//初始化 Service 组件
initInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(
sm.getString("lifecycleBase.initFail",toString()), t);
}
setStateInternal(LifecycleState.INITIALIZED, null, false);
}
我们发现这个initInternal() 方法又是 LifecycleBase的,所以我们在找对应的实现类的时候,就可以参照之前方法,找跟service 相关的,如果只有一个StandardService类
protected void initInternal() throws LifecycleException{
······此处代码省略
//这里是线程池的初始化,这个可以对照上面的图来看
for (Executor executor : findExecutors()) {
if (executor instanceof JmxEnabled) {
((JmxEnabled) executor).setDomain(getDomain());
}
//线程池 初始化
executor.init();
}
// 初始化 mapper listener
mapperListener.init();
// Initialize our defined Connectors
//可以看到这里的connector 是多个的,用加锁来保证线程安全
synchronized (connectorsLock) {
for (Connector connector : connectors) {
try {
//connector就开始初始化了
connector.init();
} catch (Exception e) {
String message = sm.getString(
"standardService.connector.initFailed", connector);
log.error(message, e);
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
throw new LifecycleException(message);
}
}
}
}
这里调用每个 Connector的init方法,再一步步跟进去,发现还是之前的套路,
在Connector 的init 方法里面又会去调用 LifecycleBase 的 initInternal() 方法,这次我们还是去找Connector里面的实现
还是贴代码
protected void initInternal() throws LifecycleException {
//其实到这里必要的组件在这个方法里面已经初始化完了
//bootstarp 方法 load 方法已经完成了
//这里还是老样子调用父类LifecycleMBeanBase 去注册bean
super.initInternal();
// Initialize adapter 这里就是初始化处理器
adapter = new CoyoteAdapter(this);
//绑定处理器 然后就是到下面 init 方法再去绑定
protocolHandler.setAdapter(adapter);
·········此处代码省略
try {
//决定是用bio 还是nio nio2 apr 这些组件去处理请求
//我们看看这个里面做了些什么
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
}
protocolHandler 这个类是一个接口,有两个实现类,我们肯定是找
AbstractProtocol这个实现类 的init 方法,在这个方法里面有一段代码也就是最后
try {
//在这里去调用,这里就是具体的绑定用 Apr 还是JIo 还是NIo
endpoint.init();
} catch (Exception ex) {
getLog().error(sm.getString("abstractProtocolHandler.initError",
getName()), ex);
throw ex;
}
那么到这里初始化的工作就全部做完了,看到这里肯定晕了。
image.png
Connector 、StandardService、StandardServer 他们都是Lifecycle的子类,其实到最后才发现整个 初始化过程都是围绕着 Lifecycle init() 和 LifecycleBase initInternal() 方法来实现的。
其实这个初始化的过程,就是用 责任链的调用模式来实现的, 一个链接着一个链来的任务来,最终完成所有的初始化。
华丽的分割线
初始化完成了,那我们再去看看启动,回到 Bootstrap 的main 方法
不说废话直接上图
if (command.equals("startd")) {
args[args.length - 1] = "start";
//先初始化一个必要的组件 如server connetor service
//这里的daemon 是就是 Bootstrap自己
daemon.load(args);
//开始加载Engine 下面相关东西,像Host Conetxt weapp
daemon.start();
}
public void start()
throws Exception {
//还是跟之前是一样的方法 反射调用catalina里面的start 方法
if( catalinaDaemon==null ) init();
Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
method.invoke(catalinaDaemon, (Object [])null);
}
我们再看 catalina 里面的start 方法
public void start() {
if (getServer() == null) {
load();
}
if (getServer() == null) {
log.fatal("Cannot start server. Server instance is not configured.");
return;
}
long t1 = System.nanoTime();
//前面都是做一些判空的操作,下面server 开始启动
// Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
}
我们按照之前的思维来分析 这个start 方法肯定又是Lifecycle 接口的一个方法,我们再去找相关的实现类 LifecycleBase,在代码中又调用了自己的startInternal方法,所以我们还是找相关的实现类StandardServer
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
//加载一些资源文件
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
// 跟之前的方式一样 ,开始每一个service启动
services[i].start();
}
}
}
我们跟到StandardService 的 startInternal方法
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) {
//这个地方就是 启动Engine、Host、context 这些组件
container.start();
}
}
synchronized (executors) {
for (Executor executor: executors) {
//启动线程池
executor.start();
}
}
//以及一些监听器
mapperListener.start();
// Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
//启动container 连接器管理
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
我们可以看到 connector 和 executor 的组件启动。
这里我们继续 Connector 的 startInternal() 方法
protected void startInternal() throws LifecycleException {
// Validate settings before starting
if (getPort() < 0) {
throw new LifecycleException(sm.getString(
"coyoteConnector.invalidPort", Integer.valueOf(getPort())));
}
setState(LifecycleState.STARTING);
try {
//这里就跟处理请求的,模式 是Bio NIO ···等方式, 这个在之前初始化的时候就已经选择好了
protocolHandler.start();
} catch (Exception e) {
String errPrefix = "";
if(this.service != null) {
errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
}
throw new LifecycleException
(errPrefix + " " + sm.getString
("coyoteConnector.protocolHandlerStartFailed"), e);
}
}
上面代码中 我们先看下 container.start() 这里,点进去发现这里是调用的ContainerBase 这个类startInternal()方法
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
logger = null;
getLogger();
Cluster cluster = getClusterInternal();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
Realm realm = getRealmInternal();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<>();
//通过责任链的 调用 不同的调用子类的start
//这里的子类 有 Engine、Host、context 这些
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
boolean fail = false;
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
setState(LifecycleState.STARTING);
// Start our thread
threadStart();
}
关注 new StartChild(children[i] )这段代码
这里会调用 engine 子容器的 start 方法。也就是Host,Host 会将一个一个的项目编译后的class 文件加进来
protected synchronized void startInternal() throws LifecycleException {
// Set error report valve
//
String errorValve = getErrorReportValveClass();
if ((errorValve != null) && (!errorValve.equals(""))) {
try {
boolean found = false;
Valve[] valves = getPipeline().getValves();
for (Valve valve : valves) {
if (errorValve.equals(valve.getClass().getName())) {
found = true;
break;
}
}
if(!found) {
Valve valve =
(Valve) Class.forName(errorValve).newInstance();
getPipeline().addValve(valve);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString(
"standardHost.invalidErrorReportValveClass",
errorValve), t);
}
}
super.startInternal();
}
最后又去调用父类的startInternal(),然后 调用 父类里面的threadStart() 方法
protected void threadStart() {
if (thread != null)
return;
if (backgroundProcessorDelay <= 0)
return;
threadDone = false;
String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
//每个子类的run方法 任务
thread = new Thread(new ContainerBackgroundProcessor(), threadName);
thread.setDaemon(true);
thread.start();
}
ContainerBackgroundProcessor 是实现了 Runnable d 线程类
processChildren 方法 里面去处理 各个子类的线程
container.backgroundProcess(); 这个是各个子类的事件的触发器
这个方法最后 fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null)
这一段是调用LifecycleSupport 类
public void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
LifecycleListener interested[] = listeners;
for (int i = 0; i < interested.length; i++)
interested[i].lifecycleEvent(event);
}
然后又会用调用 LifecycleListener lifecycleEvent这个接口的方法
这个接口里面我们看到有很多实现
image.png
其实可以看出很多子类的具体任务都是在这里处理的。
我们找一下实现 HostConfig 里面的实现 lifecycleEvent方法
的check()方法
protected void check() {
if (host.getAutoDeploy()) {
// Check for resources modification to trigger redeployment
DeployedApplication[] apps =
deployed.values().toArray(new DeployedApplication[0]);
for (int i = 0; i < apps.length; i++) {
if (!isServiced(apps[i].name))
checkResources(apps[i]);
}
// Check for old versions of applications that can now be undeployed
if (host.getUndeployOldVersions()) {
checkUndeploy();
}
// Hotdeploy applications
//开始部署应用
deployApps();
}
}
这个地方就是开始部署应用了。
protected void deployApps() {
//部署web 项目
File appBase = host.getAppBaseFile();
//找到config的配置文件路径
File configBase = host.getConfigBaseFile();
String[] filteredAppPaths = filterAppPaths(appBase.list());
// Deploy XML descriptors from configBase
deployDescriptors(configBase, configBase.list());
// Deploy WARs
//这个filteredAppPaths 是返回这个路径下面 所有的文件夹及文件名
deployWARs(appBase, filteredAppPaths);
// Deploy expanded folders
deployDirectories(appBase, filteredAppPaths);
}
到这个地方 整个tomcat 的启动流程就完了。