|
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 |
|
|