1)bin目录下的bootstrap.jar中的main方法启动Tomcat

org.apache.catalina.startup.Bootstrap类下的main方法

可以看到Bootstrap类使用单例方式在main方法中初始化Bootstrap对象

private static Bootstrap daemon = null;
private Object catalinaDaemon = null;
protected ClassLoader commonLoader = null;
protected ClassLoader catalinaLoader = null;
protected ClassLoader sharedLoader = null;

 调用Bootstrap对象的init()方法

public static void main(String[] args)
{
if (daemon == null)
{
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
}
try
{
String command = "start";
if (args.length > 0) {
command = args[(args.length - 1)];
} if (command.equals("startd")) {
args[(args.length - 1)] = "start";
daemon.load(args);
daemon.start();
} else if (command.equals("stopd")) {
args[(args.length - 1)] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
} 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(new StringBuilder().append("Bootstrap: command \"").append(command).append("\" does not exist.").toString());
}
}
catch (Throwable t) {
if (((t instanceof InvocationTargetException)) && (t.getCause() != null))
{
t = t.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}

Bootstrap对象的init()方法,引导类Bootstrap负责引导,在其init方法内部创建容器启动所需的类加载器,以及用于JMX监控的MBeanServer

public void init()
throws Exception
{
setCatalinaHome();
setCatalinaBase(); initClassLoaders(); Thread.currentThread().setContextClassLoader(this.catalinaLoader); SecurityClassLoad.securityClassLoad(this.catalinaLoader); if (log.isDebugEnabled())
log.debug("Loading startup class");
Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); 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] = this.sharedLoader;
Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); this.catalinaDaemon = startupInstance;
}

仍然在Bootstrap类中,初始化所需要的类加载器

private void initClassLoaders()
{
try
{
this.commonLoader = createClassLoader("common", null);
if (this.commonLoader == null)
{
this.commonLoader = getClass().getClassLoader();
}
this.catalinaLoader = createClassLoader("server", this.commonLoader);
this.sharedLoader = createClassLoader("shared", this.commonLoader);
} catch (Throwable t) {
handleThrowable(t);
log.error("Class loader creation threw exception", t);
System.exit(1);
}
}

 

我们继续看到main方法中调用了Bootstrap对象的load(args)方法和start()方法

daemon.load(args);
daemon.start();

我们看到load(args)方法,Bootstrap调用Catalina的load()方法加载Server的配置(也就是server.xml),将加载的配置信息委托给Digester类进行相关内容的解析。

通过反射调用了Bootstrap对象中catalinaDaemon对象的load()方法,

private void load(String[] arguments)
throws Exception
{
String methodName = "load";
Object[] param;
Class<?>[] paramTypes;
Object[] param; if ((arguments == null) || (arguments.length == 0)) {
Class<?>[] paramTypes = null;
param = null;
} else {
paramTypes = new Class[1];
paramTypes[0] = arguments.getClass();
param = new Object[1];
param[0] = arguments;
}
Method method = this.catalinaDaemon.getClass().getMethod(methodName, paramTypes); if (log.isDebugEnabled())
log.debug(new StringBuilder().append("Calling startup class ").append(method).toString());
method.invoke(this.catalinaDaemon, param);
}

  

我们可以看到在上面的init()方法中初始化了org.apache.catalina.startup.Catalina对象,通过之前初始化的catalinaLoader类加载器

该类在lib包下的catalina.jar包中

 Class<?> startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");

    Object startupInstance = startupClass.newInstance();

    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] = this.sharedLoader;
Method method = startupInstance.getClass().getMethod(methodName, paramTypes); method.invoke(startupInstance, paramValues); this.catalinaDaemon = startupInstance;

  

我们看该类中的load方法是如何加载server.xml文件的。

public void load()
{
long t1 = System.nanoTime(); initDirs(); initNaming(); Digester digester = createStartDigester(); InputSource inputSource = null;
InputStream inputStream = null;
File file = null;
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", new Object[] { 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", new Object[] { getConfigFile() }), e);
}
}
} 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", new Object[] { "server-embed.xml" }), e);
}
}
} if ((inputStream == null) || (inputSource == null)) {
if (file == null) {
log.warn(sm.getString("catalina.configFail", new Object[] { getConfigFile() + "] or [server-embed.xml]" }));
}
else {
log.warn(sm.getString("catalina.configFail", new Object[] { file.getAbsolutePath() })); if ((file.exists()) && (!file.canRead())) {
log.warn("Permissions incorrect, read permission is not allowed on the file.");
}
}
return;
}
try
{
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource); try
{
inputStream.close();
}
catch (IOException e) {} getServer().setCatalina(this);
}
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) {}
} initStreams(); try
{
getServer().init();
} catch (LifecycleException e) {
if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
throw new Error(e);
}
log.error("Catalina.start", e);
} long t2 = System.nanoTime();
if (log.isInfoEnabled()) {
log.info("Initialization processed in " + (t2 - t1) / 1000000L + " ms");
}
} public void load(String[] args)
{
try
{
if (arguments(args)) {
load();
}
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
protected boolean arguments(String[] args)
{
boolean isConfig = false; if (args.length < 1) {
usage();
return false;
} for (int i = 0; i < args.length; i++) {
if (isConfig) {
this.configFile = args[i];
isConfig = false;
} else if (args[i].equals("-config")) {
isConfig = true;
} else if (args[i].equals("-nonaming")) {
setUseNaming(false);
} else { if (args[i].equals("-help")) {
usage();
return false; }
if (args[i].equals("start")) {
this.starting = true;
this.stopping = false;
} else if (args[i].equals("configtest")) {
this.starting = true;
this.stopping = false;
} else if (args[i].equals("stop")) {
this.starting = false;
this.stopping = true;
} else {
usage();
return false;
}
}
}
return true;
}

看到Catalina类当中的变量,表明解析文件的位置。

protected String configFile = "conf/server.xml";
protected File configFile()
{
File file = new File(this.configFile);
if (!file.isAbsolute()) {
file = new File(System.getProperty("catalina.base"), this.configFile);
}
return file;
}

看到configFile方法创建File对象的过程

我们将看到load方法中调用getServer().init()调用 Server对象的init方法。

Catalina获取到Server的配置信息后,执行StandardServer容器的init()方法。Tomcat的所有容器类都实现了统一的Lifecycle接口,由基类LifecycleBase提供统一的init方法来负责处理容器的状态,调用模板方法initInternal来处理各个容器自身所负责的内容。关于Tomcat的容器结构可以参看本系列文章的《Tomcat7源码解读(一)——容器静态结构概述》。StandardServer容器在其initInternal()方法中完成Mbean的设定,GlobalNamingResources的初始化和类加载器的设置。然后执行StandardService容器的init方法。

StandardService同StandardServer容器,由基类LifecycleBase完成容器的生命周期状态设定,而在initInternal()方法中启动Container,Executor,Connector的init方法

StandardService类位于lib包下的catalina.jar包中,

org.apache.catalina.core.StandardService的父类中有init方法,

public final synchronized void init()
throws LifecycleException
{
if (!this.state.equals(LifecycleState.NEW)) {
invalidTransition("before_init");
}
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", new Object[] { toString() }), t);
} setStateInternal(LifecycleState.INITIALIZED, null, false);
}

是在org.apache.catalina.util.LifecycleBase类当中,调用了initInternal()方法。

看到LifecyceBase类的父类中

protected void initInternal()
throws LifecycleException
{
if (this.oname == null) {
this.mserver = Registry.getRegistry(null, null).getMBeanServer(); this.oname = register(this, getObjectNameKeyProperties());
}
}
protected void initInternal()
throws LifecycleException
{
super.initInternal(); this.onameStringCache = register(new StringCache(), "type=StringCache"); MBeanFactory factory = new MBeanFactory();
factory.setContainer(this);
this.onameMBeanFactory = register(factory, "type=MBeanFactory"); this.globalNamingResources.init(); if (getCatalina() != null) {
ClassLoader cl = getCatalina().getParentClassLoader(); 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) {}catch (IOException e) {}
}
}
} cl = cl.getParent();
}
} for (int i = 0; i < this.services.length; i++) {
this.services[i].init();
}
}

  

看到Bootstrap类当中调用玩load方法之后,开始调用start方法,方法也是调用Catalina类当中的start方法来启动Tomcat

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(); try
{
getServer().start();
} catch (LifecycleException e) {
log.error("Catalina.start: ", e);
} long t2 = System.nanoTime();
if (log.isInfoEnabled()) {
log.info("Server startup in " + (t2 - t1) / 1000000L + " ms");
} if (this.useShutdownHook) {
if (this.shutdownHook == null) {
this.shutdownHook = new CatalinaShutdownHook();
}
Runtime.getRuntime().addShutdownHook(this.shutdownHook); LogManager logManager = LogManager.getLogManager();
if ((logManager instanceof ClassLoaderLogManager)) {
((ClassLoaderLogManager)logManager).setUseShutdownHook(false);
}
} if (this.await) {
await();
stop();
}
}

看到调用的还是StandardServer类的start方法来启动Tomcat容器

看到类似于init的方式,我们看到也是通过调用org.apache.catalina.util.LifeCycleBase类的start方法调用一系列的startInternal方法来启动的

public final synchronized void start()
throws LifecycleException
{
if ((LifecycleState.STARTING_PREP.equals(this.state)) || (LifecycleState.STARTING.equals(this.state)) || (LifecycleState.STARTED.equals(this.state)))
{
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted", new Object[] { toString() }), e);
}
else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted", new Object[] { toString() }));
} return;
} if (this.state.equals(LifecycleState.NEW)) {
init();
} else if (this.state.equals(LifecycleState.FAILED)) {
stop();
} else if ((!this.state.equals(LifecycleState.INITIALIZED)) && (!this.state.equals(LifecycleState.STOPPED)))
{
invalidTransition("before_start");
} setStateInternal(LifecycleState.STARTING_PREP, null, false);
try
{
startInternal();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
setStateInternal(LifecycleState.FAILED, null, false);
throw new LifecycleException(sm.getString("lifecycleBase.startFail", new Object[] { toString() }), t);
} if ((this.state.equals(LifecycleState.FAILED)) || (this.state.equals(LifecycleState.MUST_STOP)))
{
stop();
}
else
{
if (!this.state.equals(LifecycleState.STARTING)) {
invalidTransition("after_start");
} setStateInternal(LifecycleState.STARTED, null, false);
}
}

  

Tomcat启动分析(Tomcat7.0)的更多相关文章

  1. Tomcat启动分析(转自:http://docs.huihoo.com/apache/tomcat/heavyz/01-startup.html)

    Tomcat启动分析 1 - Tomcat Server的组成部分 1.1 - Server A Server element represents the entire Catalina servl ...

  2. [转]Tomcat启动分析

    [转]Tomcat启动分析 原帖 http://docs.huihoo.com/apache/tomcat/heavyz/01-startup.html 以下摘录了部分 --------------- ...

  3. Tomcat启动分析(我们为什么要配置CATALINA_HOME环境变量)

    原文:http://www.cnblogs.com/heshan664754022/archive/2013/03/27/2984357.html Tomcat启动分析(我们为什么要配置CATALIN ...

  4. Tomcat启动分析(二)-自己编译Tomcat

    为了方便分析Tomcat源码,利用大家习惯的方式来进行Debug调试,那么如何将Tomcat源码导入到Eclipse呢,这就是本文的重点 1 准备 1.1 获取Tomcat源码 获取tomcat源码有 ...

  5. Tomcat启动分析(一)-从脚本到main函数分析

    当我们在Linux下启动tomcat的时候,通过ps查看其进程信息为,接下来的内容我们就以此进行分析: [tomcat@fdd ~]$ ps -ef |grep java tomcat : tty1 ...

  6. SpringBoot源码解析:tomcat启动分析

    >> spring与tomcat的启动分析:war包形式 tomcat:xml加载规范 1.contex-param: 初始化参数 2.listener-class: contextloa ...

  7. Tomcat启动分析

    [转自] http://docs.huihoo.com/apache/tomcat/heavyz/01-startup.html 1 - Tomcat Server的组成部分 1.1 - Server ...

  8. 【推荐】CentOS安装Tomcat-7.0.57+启动配置+安全配置+性能配置

    注:以下所有操作均在CentOS 6.5 x86_64位系统下完成. #准备工作# 在安装Tomcat之前,请确保已经安装了JDK-1.7环境,具体见<CentOS安装JDK-1.7>. ...

  9. Tomcat7.0源代码分析——启动与停止服务原理

    前言 熟悉Tomcat的project师们.肯定都知道Tomcat是怎样启动与停止的. 对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处 ...

随机推荐

  1. WinForm TextBox自定义扩展方法数据验证

    本文转载:http://www.cnblogs.com/gis-crazy/archive/2013/03/17/2964132.html 查看公司项目代码时,存在这样一个问题:winform界面上有 ...

  2. LCD深度剖析

    LCD 深度剖析 来源:http://blog.csdn.net/hardy_2009/article/details/6922900 http://blog.csdn.net/jaylondon/a ...

  3. 了解node.js

    转载自http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb 当我向人们介绍nod ...

  4. [TypeScript] Using Lodash in TypeScript with Typings and SystemJS

    One of the most confusing parts of getting started with TypeScript is figuring out how to use all th ...

  5. TCP keepalive under Linux

    TCP Keepalive HOWTO Prev   Next 3. Using TCP keepalive under Linux Linux has built-in support for ke ...

  6. JDBC Transaction Management Example---reference

    In this post, we want to talk about JDBC Transactions and how we can manage the operations in a data ...

  7. readonly时禁用删除键,readonly按删除键后页面后退解决方案

    readonly时禁用删除键, readonly按删除键后页面后退解决方案 >>>>>>>>>>>>>>>&g ...

  8. JS如何封装一些列方法为一个对象的操作,然后集中管理这些操作,方便修改和调用

    var Api = { ajax:{ // 添加项目 旧! add_project : function(pro_name, html, css, js,callback) { $.post(&quo ...

  9. C#入门教程(二)–C#常用快捷键、变量、类型转换-打造C#学习教程

    C#入门教程(一)–.Net平台技术介绍.C#语言及开发工具介绍-打造C#学习教程 上次教程主要介绍了.Net平台以及C#语言的相关介绍.以及经典程序案例,helloworld程序. 初来乍到,第一次 ...

  10. js中 的这些距离你知道吗?