浅析Tomcat之Bootstrap类

Tomcat的启动类是Bootstrap,它承担着管理Catalina的责任.看其main方法可以知道它首先是实例化一个Bootstrap实例,这是一个主线程.该实例创建后立即进行初始化,次调用是一个很复杂的过程.它包含了Tomcat的很多初始化工作,接着是把该实例赋值给静态变量daemon.然后才是执行相应的启动或者停止命令.

首先,看看Bootstrap的init方法,代码如下:

setCatalinaHome();
setCatalinaBase();

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

catalinaDaemon = startupInstance;

setCatalinaHome方法是设置系统变量catalina.home.如果系统中没有设置这个变量的话默认是当前的工作目录.setCatalinaBase是设置变量catalina.base,与setCatalinaHome方法类似.initClassLoaders是初始化类加载器.这些类加载器是通过配置文件来进行配置的,本文稍后进行解析.接着是实例化org.apache.catalina.startup.Catalina这个类,并设置它的类加载器.这个类才是Tomcat提供服务的地方.Bootstrap不过是为了外部对Catalina进行控制的媒介.我们可以看到Bootstrap执行start或者stop等方法都是对catalinaDaemon进行操作的,也就是控制catalina的启动或者停止.

commonLoader = createClassLoader("common", null);
if( commonLoader == null ) {
	// no config file, default to this loader - we might be in a 'single' env.
	commonLoader=this.getClass().getClassLoader();
}
catalinaLoader = createClassLoader("server", commonLoader);
sharedLoader = createClassLoader("shared", commonLoader);

 上述代码是initClassLoaders的主体它是调用createClassLoader来创建ClassLoader的.其主要代码如下

String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
	return parent;

value = replace(value);

List<Repository> repositories = new ArrayList<Repository>();

StringTokenizer tokenizer = new StringTokenizer(value, ",");
while (tokenizer.hasMoreElements()) {
	String repository = tokenizer.nextToken().trim();
	if (repository.length() == 0) {
		continue;
	}

	// Check for a JAR URL repository
	try {
		@SuppressWarnings("unused")
		URL url = new URL(repository);
		repositories.add(
				new Repository(repository, RepositoryType.URL));
		continue;
	} catch (MalformedURLException e) {
		// Ignore
	}

	// Local repository
	if (repository.endsWith("*.jar")) {
		repository = repository.substring
			(0, repository.length() - "*.jar".length());
		repositories.add(
				new Repository(repository, RepositoryType.GLOB));
	} else if (repository.endsWith(".jar")) {
		repositories.add(
				new Repository(repository, RepositoryType.JAR));
	} else {
		repositories.add(
				new Repository(repository, RepositoryType.DIR));
	}
}

ClassLoader classLoader = ClassLoaderFactory.createClassLoader
	(repositories, parent);

// Retrieving MBean server
MBeanServer mBeanServer = null;
if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
	mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
} else {
	mBeanServer = ManagementFactory.getPlatformMBeanServer();
}

// Register the server classloader
ObjectName objectName =
	new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
mBeanServer.registerMBean(classLoader, objectName);

return classLoader;

 CatalinaProperties对应着Tomcat目录下的catalina.propertis.默认的配置有common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar也就是配置了commonClassLoader的类路径.这里就指定了Catalina所能load的类的路径.因为init在实例化Catalina实例后调用了setParentClassLoader把initClassLoaders中初始化好的自定义ClassLoader类设置给Catalina.

经过上述步骤后Bootstrap基本上已经初始化好,接下来就是命令行中传入的是何种命令,执行相应的方法.

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("Bootstrap: command \"" + command + "\" does not exist.");
}

 默认执行的是start命令,也就是调用了Bootstrap的start方法.该方法是启动Tomcat连接器和容器.在以后的博文中进行解读.

 

 

首发于泛泛之辈 http://www.lihongkun.com/archives/84

猜你喜欢

转载自lihkstyle.iteye.com/blog/1944389