Tomcat启动分析(Tomcat7.0)
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)的更多相关文章
- 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 ...
- [转]Tomcat启动分析
[转]Tomcat启动分析 原帖 http://docs.huihoo.com/apache/tomcat/heavyz/01-startup.html 以下摘录了部分 --------------- ...
- Tomcat启动分析(我们为什么要配置CATALINA_HOME环境变量)
原文:http://www.cnblogs.com/heshan664754022/archive/2013/03/27/2984357.html Tomcat启动分析(我们为什么要配置CATALIN ...
- Tomcat启动分析(二)-自己编译Tomcat
为了方便分析Tomcat源码,利用大家习惯的方式来进行Debug调试,那么如何将Tomcat源码导入到Eclipse呢,这就是本文的重点 1 准备 1.1 获取Tomcat源码 获取tomcat源码有 ...
- Tomcat启动分析(一)-从脚本到main函数分析
当我们在Linux下启动tomcat的时候,通过ps查看其进程信息为,接下来的内容我们就以此进行分析: [tomcat@fdd ~]$ ps -ef |grep java tomcat : tty1 ...
- SpringBoot源码解析:tomcat启动分析
>> spring与tomcat的启动分析:war包形式 tomcat:xml加载规范 1.contex-param: 初始化参数 2.listener-class: contextloa ...
- Tomcat启动分析
[转自] http://docs.huihoo.com/apache/tomcat/heavyz/01-startup.html 1 - Tomcat Server的组成部分 1.1 - Server ...
- 【推荐】CentOS安装Tomcat-7.0.57+启动配置+安全配置+性能配置
注:以下所有操作均在CentOS 6.5 x86_64位系统下完成. #准备工作# 在安装Tomcat之前,请确保已经安装了JDK-1.7环境,具体见<CentOS安装JDK-1.7>. ...
- Tomcat7.0源代码分析——启动与停止服务原理
前言 熟悉Tomcat的project师们.肯定都知道Tomcat是怎样启动与停止的. 对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处 ...
随机推荐
- Hibernate—第一个案例
百度百科上是这样写道的:Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可 ...
- [Node.js] Node.js Buffers
>> node >>fs.readFile('finnish.txt', function(err,data){ console.log(data); }); // Outpu ...
- 使用tuple返回多个值
17.4编写并测试findbook函数 #include<iostream> #include<vector> #include<string> #include& ...
- mysql的limit、order by和group by的用法
程序执行会重复 用mysql很长时间,limit是分页的一个好工具, select * from table_a where num = 4 limit 1,10, select * from tab ...
- Android(java)学习笔记178:BroadcastReceiver之 自定义广播
广播使用: 电台:对外发送信号.---------电台发送广播(可以自定义) 收音机:接收电台的信号.-----广播接收者 这里,我们就说明自定 ...
- 如何创建一个自己的【Composer/Packagist】包
首先让我们踏着欢快的脚步去Github创建一个新库,这里取名 composer-car,又欢快的将它克隆到本地: $ git clone git@github.com:victorruan/compo ...
- [转载]SharePoint 网站管理-PowerShell
1. 显示场中所有可用的网站集 Get-SPSite Get-SPSite 2. 显示某一Web应用程序下可用的网站集 Get-SPSite –WebApplication "SharePo ...
- 27、Jquery 事件
Jquery 事件 在javascript中事件调用方式为onclick.onmouseover等,在jquery中 使用事件无需写前面的on bind()方法 为元素绑定事件 $("#id ...
- angularJs ionic phoneGap 分享
由于坑较多 就如“天下难事,必作于易吧” 最近有机会接触到了git node angularJs ionic phoneGap 很开森也很痛苦 分享如下 推荐的几个博客地址: ionic开发插件之n ...
- KinSlideshow参数设置说明
[引用来自:http://blog.sina.com.cn/s/blog_4f4f4a5901014zn1.html] Jquery.KinSlideshow参数设置说明: 附:所有参数列表 in ...