Tomcat源码系列:
- Tomcat初始化源码流程分析(图解及源码注释) (一)
- Tomcat初始化源码流程分析(图解及源码注释) (二)
- Tomcat启动源码流程分析(图解及源码注释) (三)
- Tomcat启动源码流程分析(图解及源码注释) (四)
- Tomcat请求源码流程分析(图解及源码注释) (五)
- Tomcat请求源码流程分析(图解及源码注释) (六)
本章为Tomcat初始化流程的第一章,主要内容有Bootstrap启动类的初始化,Catalina实例的初始化,以及Server实例的初始化.
Tomcat初始化源码不适用于新手
文章内容只有部分流程的源码分析,通过代码注释的方法,仅适用于Tomcat的源码有一定的了解的同学
目录
2.1解析server.xml或server-embed.xml文件
2.2.1 getServer().init() ---> StandardServer.initInternal()
初始化流程图如下:
1.Tomcat启动入口
1.1main函数
public static void main(String args[]) {
synchronized (daemonLock) {
if (daemon == null) {
// Don't set daemon until init() has completed
//实例化一个BootStrap对象
Bootstrap bootstrap = new Bootstrap();
try {
//开始初始化BootStrap对象
//其中包括初始化三大类加载器
//初始化Catalina实例,并设置为静态变量(初始化Catalina实例,设置shared类加载器)
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
//将静态变量daemon设置为初始化完成的BootStrap实例
//确定在Tomcat关闭时关闭的是同一个Tomcat实例
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.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
}
//根据不同的启动方法进行加载
try {
String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
//实际调用为Catalina实例的load方法,通过反射调用.
daemon.load(args);
//实际调用为Catalina实例的start方法,通过反射调用.
daemon.start();
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
//实际调用为Catalina实例的load方法,通过反射调用.
daemon.load(args);
//实际调用为Catalina实例的start方法,通过反射调用.
daemon.start();
//当Catalina实例获取失败时,系统推出
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not exist.");
}
} catch (Throwable t) {
//通过抓取异常推出程序
// Unwrap the Exception for clearer error reporting
if (t instanceof InvocationTargetException &&
t.getCause() != null) {
t = t.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
1.1.1bootstrap实例的init方法
public void init() throws Exception {
//实例化三大类加载器
initClassLoaders();
//设置线程上下文加载器
//Catalina加载器负责加载Tomcat需要的jar包
Thread.currentThread().setContextClassLoader(catalinaLoader);
SecurityClassLoad.securityClassLoad(catalinaLoader);
// Load our startup class and call its process() method
if (log.isDebugEnabled())
log.debug("Loading startup class");
//准备初始化Catalina实例
Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.getConstructor().newInstance();
// Set the shared extensions class loader
//反射设置shared类加载器,调用方法为setParentClassLoader
if (log.isDebugEnabled())
log.debug("Setting startup class properties");
String methodName = "setParentClassLoader";
Class<?> paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);
//初始化完成,将静态变量设置为初始化完成的Catalina实例对象.
catalinaDaemon = startupInstance;
}
1.1.2 反射调用Catalina实例的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);
}
2.Catalina实例的load方法
2.1解析server.xml或server-embed.xml文件
if (loaded) {
return;
}
loaded = true;
long t1 = System.nanoTime();
initDirs();
// Before digester - it may be needed
initNaming();
//初始化用于解析server.xml的类
Digester digester = createStartDigester();
InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
//尝试获取conf/server.xml
try {
try {
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);
}
}
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream(getConfigFile());
inputSource = new InputSource
(getClass().getClassLoader()
.getResource(getConfigFile()).toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail",
getConfigFile()), e);
}
}
}
//在获取conf/server.xml失败时
//获取server-embed.xml
// This should be included in catalina.jar
// Alternative: don't bother with xml, just create it manually.
if (inputStream == null) {
try {
inputStream = getClass().getClassLoader()
.getResourceAsStream("server-embed.xml");
inputSource = new InputSource
(getClass().getClassLoader()
.getResource("server-embed.xml").toString());
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("catalina.configFail",
"server-embed.xml"), e);
}
}
}
//在两大xml文件都没有的情况下,直接返回
if (inputStream == null || inputSource == null) {
if (file == null) {
log.warn(sm.getString("catalina.configFail",
getConfigFile() + "] or [server-embed.xml]"));
} else {
log.warn(sm.getString("catalina.configFail",
file.getAbsolutePath()));
if (file.exists() && !file.canRead()) {
log.warn("Permissions incorrect, read permission is not allowed on the file.");
}
}
return;
}
try {
//通过server.xml配置server实例
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 {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// Ignore
}
}
}
2.2 初始化Server实例
getServer().setCatalina(this);
getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
// Stream redirection
initStreams();
// Start the new server
try {
// 初始化Server实例,注意:在Server实例中没有init方法
// 但是在Server的父类LifecycleMBeanBase的父类LifecycleBase中存在init方法
// 同时在LifecycleBase中调用了initInternal()抽象方法,该方法由StandardServer子类实现
// 所以实际上init方法调用的为initInternal方法
//与后期的start方法同理
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");
}
2.2.1 getServer().init() ---> 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");
//注册一个Bean工厂,管理server
MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
onameMBeanFactory = register(factory, "type=MBeanFactory");
// Register the naming resources
// 初始化全局资源
globalNamingResources.init();
// Populate the extension validator with JARs from common and shared
// class loaders
if (getCatalina() != null) {
ClassLoader cl = getCatalina().getParentClassLoader();//shared类加载器
//加载可以被分享的jar包
// Walk the class loader hierarchy. Stop at the system class loader.
// This will add the shared (if present) and common class loaders
while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
if (cl instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url : urls) {
if (url.getProtocol().equals("file")) {
try {
File f = new File (url.toURI());
if (f.isFile() &&
f.getName().endsWith(".jar")) {
ExtensionValidator.addSystemResource(f);
}
} catch (URISyntaxException e) {
// Ignore
} catch (IOException e) {
// Ignore
}
}
}
}
// ? ? ?如果不能被加载,则向上级加载器加载
cl = cl.getParent();
}
}
// 初始化service的集合
for (Service service : services) {
//代码跳转至StandardService类的initInternal方法中
service.init();
}