Tomcat6源码解析--Bootstrap.java

package org.apache.catalina.startup;

src file:http://svn.apache.org/repos/asf/tomcat/tc6.0.x/tags/TOMCAT_6_0_42/java/org/apache/catalina/startup/Bootstrap.java

goal:了解tomcat启动的大致流程

欢迎各位指正其中的错误和不足

入口main方法


public static void main(String args[]) {

	if (daemon == null) {
		daemon = new Bootstrap();
		try {
			daemon.init();//init(完成了加载环境变量和类加载器的工作)
		} catch (Throwable t) {
			t.printStackTrace();
			return;
		}
	}

	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);
			// 信息: Initialization processed in 3024454 ms
			daemon.load(args);
			// 启动server
			daemon.start();
		} else if (command.equals("stop")) {
			daemon.stopServer(args);
		} else {
			log.warn("Bootstrap: command \"" + command + "\" does not exist.");
		}
	} catch (Throwable t) {
		t.printStackTrace();
	}
}



以上是bootstrap类的main方法,里边逐步调用了一些用于初始化的方法.下面一一解读:

init()方法:


/**
 * Initialize daemon.
 */
public void init() throws Exception {

	// Set Catalina path
	setCatalinaHome();// 加载Catalina.Home环境变量(catalina.home)
	setCatalinaBase();// 加载Catalina.Base环境变量(catalina.base)

	initClassLoaders();// 初始化类加载器

	Thread.currentThread().setContextClassLoader(catalinaLoader);

	SecurityClassLoad.securityClassLoad(catalinaLoader);

	// Load our startup class and call its process() method
	if (log.isDebugEnabled()) {
		log.debug("Loading startup class");
	}
	Class startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
	Object startupInstance = startupClass.newInstance();

	// Set the shared extensions class loader
	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;
	// 找到org.apache.catalina.startup.Catalina#setParentClassLoader方法
	Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
	// 设置java.lang.ClassLoader为父类加载器
	method.invoke(startupInstance, paramValues);

	catalinaDaemon = startupInstance;// 设置Catalina进程
}



init()方法
  1. 对环境变量的读取,主要是读取  catalina.home\catalina.base
  2. 初始化类加载器,默认使用当前类的类加载器  this.getClass().getClassLoader();
  3. 加载了Catalina类  classLoader.loadClass("org.apache.catalina.startup.Catalina")
  4. 反射设置父类加载器  org.apache.catalina.startup.Catalina#setParentClassLoader设置java.lang.ClassLoader为ParentClassLoader

daemon.setAwait(true)方法:


/**
 * Set flag.
 */
public void setAwait(boolean await) throws Exception {

	Class paramTypes[] = new Class[1];
	paramTypes[0] = Boolean.TYPE;
	Object paramValues[] = new Object[1];
	paramValues[0] = new Boolean(await);
	// 获取Catalina类(其实是其父类Embedded)中的setAwait方法
	Method method = catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
	// 使用await参数调用
	method.invoke(catalinaDaemon, paramValues);

}



setAwait方法
  1. 这个方法并没有具体的深入研究,不过从字面意义上来看,应该是设置了一个锁.欢迎各位指正.

daemon.load(args)方法:


/**
 * Load daemon.
 */
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;
	}
	// 获取Catalina的load方法
	Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes);
	if (log.isDebugEnabled())
		log.debug("Calling startup class " + method);
	// 调用(启动一个新的服务器实例)
	method.invoke(catalinaDaemon, param);

}



daemon.load方法

  通过反射调用Catalina的load方法

**
 * Start a new server instance.
 */
public void load() {

	long t1 = System.nanoTime();

	initDirs();// 读取环境变量

	// Before digester - it may be needed

	initNaming();

	// Create and execute our Digester
	Digester digester = createStartDigester();

	InputSource inputSource = null;
	InputStream inputStream = null;
	File file = null;
	try {
		file = configFile();//获取server.xml位置
		inputStream = new FileInputStream(file);
		inputSource = new InputSource("file://" + file.getAbsolutePath());
	} catch (Exception e) {
		;
	}
	// 如果不能获取server.xml,则使用ClassLoader再查找一次
	if (inputStream == null) {
		try {
			inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile());
			inputSource = new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString());
		} catch (Exception e) {
			;
		}
	}

	// 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 ((inputStream == null) && (file != null)) {
		log.warn("Can't load server.xml from " + 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);// 加载server.xml
		inputStream.close();
	} catch (Exception e) {
		log.warn("Catalina.start using "
						   + getConfigFile() + ": " , e);
		return;
	}

	// Stream redirection
	initStreams();// 设置log

	// Start the new server
	if (getServer() instanceof Lifecycle) {
		try {
			getServer().initialize();
		} 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");

}



Catalina.load方法
  1. #initDirs()完成了读取环境变量
  2. #initNaming()设置命名空间catalina.useNaming\java.naming.factory.url.pkgs\java.naming.factory.initial  这几个命名空间没有具体研究作用,同样欢迎补充
  3. 创建Digester
  4. 读取server.xml文件
  5. #digester.push(this)
  6. #digester.parse(inputSource)使用digester解析server.xml并按照配置创建Server对象
  7. #initStreams()设置log
  8. 调用#getServer().initialize()启动server

daemon.start()方法:


/**
 * Start the Catalina daemon.
 */
public void start() throws Exception {
	if (catalinaDaemon == null)
		init();

	Method method = catalinaDaemon.getClass().getMethod("start", (Class[]) null);
	method.invoke(catalinaDaemon, (Object[]) null);

}



daemon.start方法

 

  通过反射调用Catalina的start方法

/**
 * Start a new server instance.
 */
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();
	
	// Start the new server
	if (getServer() instanceof Lifecycle) {
		try {
			((Lifecycle) getServer()).start();
		} catch (LifecycleException e) {
			log.error("Catalina.start: ", e);
		}
	}

	long t2 = System.nanoTime();
	if(log.isInfoEnabled())
		log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");

	try {
		// Register shutdown hook
		if (useShutdownHook) {
			if (shutdownHook == null) {
				shutdownHook = new CatalinaShutdownHook();
			}
			Runtime.getRuntime().addShutdownHook(shutdownHook);
			
			// If JULI is being used, disable JULI's shutdown hook since
			// shutdown hooks run in parallel and log messages may be lost
			// if JULI's hook completes before the CatalinaShutdownHook()
			LogManager logManager = LogManager.getLogManager();
			if (logManager instanceof ClassLoaderLogManager) {
				((ClassLoaderLogManager) logManager).setUseShutdownHook(
						false);
			}
		}
	} catch (Throwable t) {
		// This will fail on JDK 1.2. Ignoring, as Tomcat can run
		// fine without the shutdown hook.
	}

	if (await) {
		await();
		stop();
	}

}


Catalina.start方法
  1. 逐步启动server的生命周期
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值