Catalina
Catalina
Tomcat里的Server由 org.apache.catalina.startup.Catalina管理。Catalina类里面由 load、start、stop三个方法用来管理整个服务器的生命周期。
1、load:用于根据 conf/server.xml 文件创建Server、并调用Server的init方法进行初始化。
2、start:用于启动服务器。
3、stop:停止服务器。
start、stop方法在内部会调用Server的start和stop方法,load方法调用Server的init方法。
Server的start方法会调用Service中的start方法,Service中的start会调用Connectors和Container中的start方法。
org.apache.catalina.startup.Catalina
// 主要看 Await、load、start、stop方法
Await方法
// 设置 await值,会在start方法中服务器启动完成后来判断是否进入等待状态
public void setAwait(boolean b) {
await = b;
}
Load方法
// org.apache.catalina.startup.Catalina
public void load() {
// 已经加载就返回
if (loaded) {
return;
}
// 设置加载状态
loaded = true;
long t1 = System.nanoTime();
initDirs();
// Before digester - it may be needed
initNaming();
// Create and execute our Digester
// 通过 digester 解析 server.xml 配置文件
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
try {
try {
// 指定了 conf/server.xml
file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
}
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream(getConfigFile());
inputSource = new InputSource
(getClass().getClassLoader()
.getResource(getConfigFile()).toString());
}
}
if (inputStream == null) {
// 尝试加载 server-embed.xml
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream("server-embed.xml");
inputSource = new InputSource
(getClass().getClassLoader()
.getResource("server-embed.xml").toString());
}
}
// 依旧找不到文件,返回
if (inputStream == null || inputSource == null) {
return;
}
try {
inputSource.setByteStream(inputStream);
digester.push(this);
// 解析 xml
digester.parse(inputSource);
}
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
}
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// Stream redirection
initStreams();
// Start the new server
try {
getServer().init();
}
}
简化后的 load方法:
Digester digester = createStartDigester();
File file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource(file.toURI().toURL().toString());
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
getServer().setCatalina(this);
getServer().init();
Digester 查相关资料:Java解析xml主要由DOM4J(一次读取到内存并解析)、SAX(一次解析一部分),digester本身采用SAX的解析方式,并提供了一层包装,对使用者更加友好,后来独立出来成为apache的Commons下面的一个单独的子项目。
Start方法
/**
* Start a new server instance.
*/
public void start() {
if (getServer() == null) {
load();
}
// Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
return;
}
// 注册shutdown钩子函数
if (useShutdownHook) {
if (shutdownHook == null) {
shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(shutdownHook);
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
false);
}
}
if (await) {
await();
stop();
}
}
Stop方法
/**
* Stop an existing server instance.
*/
public void stop() {
try {
// 为了避免调用两次钩子函数,首先移除钩子函数
if (useShutdownHook) {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
LogManager logManager = LogManager.getLogManager();
if (logManager instanceof ClassLoaderLogManager) {
((ClassLoaderLogManager) logManager).setUseShutdownHook(
true);
}
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
}
// 关闭服务
Server s = getServer();
LifecycleState state = s.getState();
if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0
&& LifecycleState.DESTROYED.compareTo(state) >= 0) {
// Nothing to do. stop() was already called
} else {
s.stop();
s.destroy();
}
}