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);
}
}

  

上一篇:ADB连接手机的两种方式(usb数据线连接和wifi连接)


下一篇:PagedList.MVC分页