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. Hibernate—第一个案例

    百度百科上是这样写道的:Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可 ...

  2. [Node.js] Node.js Buffers

    >> node >>fs.readFile('finnish.txt', function(err,data){ console.log(data); }); // Outpu ...

  3. 使用tuple返回多个值

    17.4编写并测试findbook函数 #include<iostream> #include<vector> #include<string> #include& ...

  4. mysql的limit、order by和group by的用法

    程序执行会重复 用mysql很长时间,limit是分页的一个好工具, select * from table_a where num = 4 limit 1,10, select * from tab ...

  5. Android(java)学习笔记178:BroadcastReceiver之 自定义广播

    广播使用:               电台:对外发送信号.---------电台发送广播(可以自定义)               收音机:接收电台的信号.-----广播接收者 这里,我们就说明自定 ...

  6. 如何创建一个自己的【Composer/Packagist】包

    首先让我们踏着欢快的脚步去Github创建一个新库,这里取名 composer-car,又欢快的将它克隆到本地: $ git clone git@github.com:victorruan/compo ...

  7. [转载]SharePoint 网站管理-PowerShell

    1. 显示场中所有可用的网站集 Get-SPSite Get-SPSite 2. 显示某一Web应用程序下可用的网站集 Get-SPSite –WebApplication "SharePo ...

  8. 27、Jquery 事件

    Jquery 事件 在javascript中事件调用方式为onclick.onmouseover等,在jquery中 使用事件无需写前面的on bind()方法 为元素绑定事件 $("#id ...

  9. angularJs ionic phoneGap 分享

    由于坑较多 就如“天下难事,必作于易吧” 最近有机会接触到了git  node angularJs ionic phoneGap 很开森也很痛苦 分享如下 推荐的几个博客地址: ionic开发插件之n ...

  10. KinSlideshow参数设置说明

    [引用来自:http://blog.sina.com.cn/s/blog_4f4f4a5901014zn1.html] Jquery.KinSlideshow参数设置说明: 附:所有参数列表   in ...