Tomcat7启动分析(二)Bootstrap类中的main方法

之前分析了Tomcat的启动脚本,如果从startup.bat开始启动Tomcat的话会发现最后会调用org.apache.catalina.startup.Bootstrap里的main方法,并且传过来的最后一个命令行参数是start,接下来的启动代码分析就从这里开始。

 

先看下这个main方法的代码:

 1 /**
 2      * Main method and entry point when starting Tomcat via the provided
 3      * scripts.
 4      *
 5      * @param args Command line arguments to be processed
 6      */
 7     public static void main(String args[]) {
 8 
 9         if (daemon == null) {
10             // Don't set daemon until init() has completed
11             Bootstrap bootstrap = new Bootstrap();
12             try {
13                 bootstrap.init();
14             } catch (Throwable t) {
15                 handleThrowable(t);
16                 t.printStackTrace();
17                 return;
18             }
19             daemon = bootstrap;
20         } else {
21             // When running as a service the call to stop will be on a new
22             // thread so make sure the correct class loader is used to prevent
23             // a range of class not found exceptions.
24             Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
25         }
26 
27         try {
28             String command = "start";
29             if (args.length > 0) {
30                 command = args[args.length - 1];
31             }
32 
33             if (command.equals("startd")) {
34                 args[args.length - 1] = "start";
35                 daemon.load(args);
36                 daemon.start();
37             } else if (command.equals("stopd")) {
38                 args[args.length - 1] = "stop";
39                 daemon.stop();
40             } else if (command.equals("start")) {
41                 daemon.setAwait(true);
42                 daemon.load(args);
43                 daemon.start();
44             } else if (command.equals("stop")) {
45                 daemon.stopServer(args);
46             } else if (command.equals("configtest")) {
47                 daemon.load(args);
48                 if (null==daemon.getServer()) {
49                     System.exit(1);
50                 }
51                 System.exit(0);
52             } else {
53                 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
54             }
55         } catch (Throwable t) {
56             // Unwrap the Exception for clearer error reporting
57             if (t instanceof InvocationTargetException &&
58                     t.getCause() != null) {
59                 t = t.getCause();
60             }
61             handleThrowable(t);
62             t.printStackTrace();
63             System.exit(1);
64         }
65 
66     }

这里的daemon是Bootstrap类中的一个静态成员变量,类型就是Bootstrap,第10行的注释已经说明在调用过init方法之后才会给该变量赋值,初始时将是null,所以首先将实例化一个Bootstrap对象,接着调用init方法,该方法代码如下:

 1 /**
 2      * Initialize daemon.
 3      */
 4     public void init()
 5         throws Exception
 6     {
 7 
 8         // Set Catalina path
 9         setCatalinaHome();
10         setCatalinaBase();
11 
12         initClassLoaders();
13 
14         Thread.currentThread().setContextClassLoader(catalinaLoader);
15 
16         SecurityClassLoad.securityClassLoad(catalinaLoader);
17 
18         // Load our startup class and call its process() method
19         if (log.isDebugEnabled())
20             log.debug("Loading startup class");
21         Class<?> startupClass =
22             catalinaLoader.loadClass
23             ("org.apache.catalina.startup.Catalina");
24         Object startupInstance = startupClass.newInstance();
25 
26         // Set the shared extensions class loader
27         if (log.isDebugEnabled())
28             log.debug("Setting startup class properties");
29         String methodName = "setParentClassLoader";
30         Class<?> paramTypes[] = new Class[1];
31         paramTypes[0] = Class.forName("java.lang.ClassLoader");
32         Object paramValues[] = new Object[1];
33         paramValues[0] = sharedLoader;
34         Method method =
35             startupInstance.getClass().getMethod(methodName, paramTypes);
36         method.invoke(startupInstance, paramValues);
37 
38         catalinaDaemon = startupInstance;
39 
40     }

这里不再逐句解释代码的作用,总的来说这个方法主要做了一下几件事:1.设置catalina.home、catalina.base系统属性,2.创建commonLoader、catalinaLoader、sharedLoader三个类加载器(建议看看createClassLoader方法,里面做的事情还挺多,比如装载catalina.properties里配置的目录下的文件和jar包,后两个加载器的父加载器都是第一个,最后注册了MBean,可以用于JVM监控该对象),3.实例化一个org.apache.catalina.startup.Catalina对象,并赋值给静态成员catalinaDaemon,以sharedLoader作为入参通过反射调用该对象的setParentClassLoader方法。

 

接下来去命令行最后一个参数,按文章开头所说是start,所以将执行34行到36行的代码,将会执行Bootstrap类中的load、start方法。

 

load方法代码如下:

 1     /**
 2      * Load daemon.
 3      */
 4     private void load(String[] arguments)
 5         throws Exception {
 6 
 7         // Call the load() method
 8         String methodName = "load";
 9         Object param[];
10         Class<?> paramTypes[];
11         if (arguments==null || arguments.length==0) {
12             paramTypes = null;
13             param = null;
14         } else {
15             paramTypes = new Class[1];
16             paramTypes[0] = arguments.getClass();
17             param = new Object[1];
18             param[0] = arguments;
19         }
20         Method method =
21             catalinaDaemon.getClass().getMethod(methodName, paramTypes);
22         if (log.isDebugEnabled())
23             log.debug("Calling startup class " + method);
24         method.invoke(catalinaDaemon, param);
25 
26     }

就是通过反射调用catalinaDaemon对象的load方法,catalinaDaemon对象在上面的init方法中已经实例化过了。

 

start方法与load方法相似,也是通过反射调用catalinaDaemon对象上的start方法:

 1     /**
 2      * Start the Catalina daemon.
 3      */
 4     public void start()
 5         throws Exception {
 6         if( catalinaDaemon==null ) init();
 7 
 8         Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
 9         method.invoke(catalinaDaemon, (Object [])null);
10 
11     }

下面一篇文章将分析catalinaDaemon对象中的load、start两个方法,里面会涉及一个有趣的话题——Digester的使用。

posted @ 2013-08-21 14:01  潜台词  阅读(1254)  评论(0)    收藏  举报