首页 > 代码库 > (三)Bootstrap.jar

(三)Bootstrap.jar

catalina.bat 在最后启动了bootstrap.jar, 传递了start作为参数(如果多个参数的话,start在尾部)。 然后org.apache.catalina.startup.Bootstrap的main方法初始化了一个bootstrap守护进程,通过调用了catalina.java对应方法。

 

技术分享
  1 /*
  2  * Licensed to the Apache Software Foundation (ASF) under one or more
  3  * contributor license agreements.  See the NOTICE file distributed with
  4  * this work for additional information regarding copyright ownership.
  5  * The ASF licenses this file to You under the Apache License, Version 2.0
  6  * (the "License"); you may not use this file except in compliance with
  7  * the License.  You may obtain a copy of the License at
  8  *
  9  *      http://www.apache.org/licenses/LICENSE-2.0
 10  *
 11  * Unless required by applicable law or agreed to in writing, software
 12  * distributed under the License is distributed on an "AS IS" BASIS,
 13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  * See the License for the specific language governing permissions and
 15  * limitations under the License.
 16  */
 17 package org.apache.catalina.startup;
 18 
 19 import java.io.File;
 20 import java.lang.reflect.InvocationTargetException;
 21 import java.lang.reflect.Method;
 22 import java.net.MalformedURLException;
 23 import java.net.URL;
 24 import java.util.ArrayList;
 25 import java.util.List;
 26 import java.util.StringTokenizer;
 27 
 28 import org.apache.catalina.Globals;
 29 import org.apache.catalina.security.SecurityClassLoad;
 30 import org.apache.catalina.startup.ClassLoaderFactory.Repository;
 31 import org.apache.catalina.startup.ClassLoaderFactory.RepositoryType;
 32 import org.apache.juli.logging.Log;
 33 import org.apache.juli.logging.LogFactory;
 34 
 35 /**
 36  * Bootstrap loader for Catalina.  This application constructs a class loader
 37  * for use in loading the Catalina internal classes (by accumulating all of the
 38  * JAR files found in the "server" directory under "catalina.home"), and
 39  * starts the regular execution of the container.  The purpose of this
 40  * roundabout approach is to keep the Catalina internal classes (and any
 41  * other classes they depend on, such as an XML parser) out of the system
 42  * class path and therefore not visible to application level classes.
 43  *
 44  * @author Craig R. McClanahan
 45  * @author Remy Maucherat
 46  */
 47 public final class Bootstrap {
 48 
 49     private static final Log log = LogFactory.getLog(Bootstrap.class);
 50 
 51 
 52     // ------------------------------------------------------- Static Variables
 53 
 54 
 55     /**
 56      * Daemon object used by main.
 57      */
 58     private static Bootstrap daemon = null;
 59 
 60 
 61     // -------------------------------------------------------------- Variables
 62 
 63 
 64     /**
 65      * Daemon reference.
 66      */
 67     private Object catalinaDaemon = null;
 68 
 69 
 70     ClassLoader commonLoader = null;
 71     ClassLoader catalinaLoader = null;
 72     ClassLoader sharedLoader = null;
 73 
 74 
 75     // -------------------------------------------------------- Private Methods
 76 
 77 
 78     private void initClassLoaders() {
 79         try {
 80             commonLoader = createClassLoader("common", null);
 81             if( commonLoader == null ) {
 82                 // no config file, default to this loader - we might be in a ‘single‘ env.
 83                 commonLoader=this.getClass().getClassLoader();
 84             }
 85             catalinaLoader = createClassLoader("server", commonLoader);
 86             sharedLoader = createClassLoader("shared", commonLoader);
 87         } catch (Throwable t) {
 88             handleThrowable(t);
 89             log.error("Class loader creation threw exception", t);
 90             System.exit(1);
 91         }
 92     }
 93 
 94 
 95     private ClassLoader createClassLoader(String name, ClassLoader parent)
 96         throws Exception {
 97 
 98         String value = http://www.mamicode.com/CatalinaProperties.getProperty(name + ".loader");
 99         if ((value =http://www.mamicode.com/= null) || (value.equals("")))
100             return parent;
101 
102         value =http://www.mamicode.com/ replace(value);
103 
104         List<Repository> repositories = new ArrayList<Repository>();
105 
106         StringTokenizer tokenizer = new StringTokenizer(value, ",");
107         while (tokenizer.hasMoreElements()) {
108             String repository = tokenizer.nextToken().trim();
109             if (repository.length() == 0) {
110                 continue;
111             }
112 
113             // Check for a JAR URL repository
114             try {
115                 @SuppressWarnings("unused")
116                 URL url = new URL(repository);
117                 repositories.add(
118                         new Repository(repository, RepositoryType.URL));
119                 continue;
120             } catch (MalformedURLException e) {
121                 // Ignore
122             }
123 
124             // Local repository
125             if (repository.endsWith("*.jar")) {
126                 repository = repository.substring
127                     (0, repository.length() - "*.jar".length());
128                 repositories.add(
129                         new Repository(repository, RepositoryType.GLOB));
130             } else if (repository.endsWith(".jar")) {
131                 repositories.add(
132                         new Repository(repository, RepositoryType.JAR));
133             } else {
134                 repositories.add(
135                         new Repository(repository, RepositoryType.DIR));
136             }
137         }
138 
139         return ClassLoaderFactory.createClassLoader(repositories, parent);
140     }
141 
142     /**
143      * System property replacement in the given string.
144      * 
145      * @param str The original string
146      * @return the modified string
147      */
148     protected String replace(String str) {
149         // Implementation is copied from ClassLoaderLogManager.replace(),
150         // but added special processing for catalina.home and catalina.base.
151         String result = str;
152         int pos_start = str.indexOf("${");
153         if (pos_start >= 0) {
154             StringBuilder builder = new StringBuilder();
155             int pos_end = -1;
156             while (pos_start >= 0) {
157                 builder.append(str, pos_end + 1, pos_start);
158                 pos_end = str.indexOf(}, pos_start + 2);
159                 if (pos_end < 0) {
160                     pos_end = pos_start - 1;
161                     break;
162                 }
163                 String propName = str.substring(pos_start + 2, pos_end);
164                 String replacement;
165                 if (propName.length() == 0) {
166                     replacement = null;
167                 } else if (Globals.CATALINA_HOME_PROP.equals(propName)) {
168                     replacement = getCatalinaHome();
169                 } else if (Globals.CATALINA_BASE_PROP.equals(propName)) {
170                     replacement = getCatalinaBase();
171                 } else {
172                     replacement = System.getProperty(propName);
173                 }
174                 if (replacement != null) {
175                     builder.append(replacement);
176                 } else {
177                     builder.append(str, pos_start, pos_end + 1);
178                 }
179                 pos_start = str.indexOf("${", pos_end + 1);
180             }
181             builder.append(str, pos_end + 1, str.length());
182             result = builder.toString();
183         }
184         return result;
185     }
186 
187 
188     /**
189      * Initialize daemon.
190      */
191     public void init()
192         throws Exception
193     {
194 
195         // Set Catalina path
196         setCatalinaHome();
197         setCatalinaBase();
198 
199         initClassLoaders();
200 
201         Thread.currentThread().setContextClassLoader(catalinaLoader);
202 
203         SecurityClassLoad.securityClassLoad(catalinaLoader);
204 
205         // Load our startup class and call its process() method
206         if (log.isDebugEnabled())
207             log.debug("Loading startup class");
208         Class<?> startupClass =
209             catalinaLoader.loadClass
210             ("org.apache.catalina.startup.Catalina");
211         Object startupInstance = startupClass.newInstance();
212 
213         // Set the shared extensions class loader
214         if (log.isDebugEnabled())
215             log.debug("Setting startup class properties");
216         String methodName = "setParentClassLoader";
217         Class<?> paramTypes[] = new Class[1];
218         paramTypes[0] = Class.forName("java.lang.ClassLoader");
219         Object paramValues[] = new Object[1];
220         paramValues[0] = sharedLoader;
221         Method method =
222             startupInstance.getClass().getMethod(methodName, paramTypes);
223         method.invoke(startupInstance, paramValues);
224 
225         catalinaDaemon = startupInstance;
226 
227     }
228 
229 
230     /**
231      * Load daemon.
232      */
233     private void load(String[] arguments)
234         throws Exception {
235 
236         // Call the load() method
237         String methodName = "load";
238         Object param[];
239         Class<?> paramTypes[];
240         if (arguments==null || arguments.length==0) {
241             paramTypes = null;
242             param = null;
243         } else {
244             paramTypes = new Class[1];
245             paramTypes[0] = arguments.getClass();
246             param = new Object[1];
247             param[0] = arguments;
248         }
249         Method method =
250             catalinaDaemon.getClass().getMethod(methodName, paramTypes);
251         if (log.isDebugEnabled())
252             log.debug("Calling startup class " + method);
253         method.invoke(catalinaDaemon, param);
254 
255     }
256 
257 
258     /**
259      * getServer() for configtest
260      */
261     private Object getServer() throws Exception {
262 
263         String methodName = "getServer";
264         Method method =
265             catalinaDaemon.getClass().getMethod(methodName);
266         return method.invoke(catalinaDaemon);
267 
268     }
269 
270 
271     // ----------------------------------------------------------- Main Program
272 
273 
274     /**
275      * Load the Catalina daemon.
276      */
277     public void init(String[] arguments)
278         throws Exception {
279 
280         init();
281         load(arguments);
282 
283     }
284 
285 
286     /**
287      * Start the Catalina daemon.
288      */
289     public void start()
290         throws Exception {
291         if( catalinaDaemon==null ) init();
292 
293         Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
294         method.invoke(catalinaDaemon, (Object [])null);
295 
296     }
297 
298 
299     /**
300      * Stop the Catalina Daemon.
301      */
302     public void stop()
303         throws Exception {
304 
305         Method method = catalinaDaemon.getClass().getMethod("stop", (Class [] ) null);
306         method.invoke(catalinaDaemon, (Object [] ) null);
307 
308     }
309 
310 
311     /**
312      * Stop the standalone server.
313      */
314     public void stopServer()
315         throws Exception {
316 
317         Method method =
318             catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);
319         method.invoke(catalinaDaemon, (Object []) null);
320 
321     }
322 
323 
324    /**
325      * Stop the standalone server.
326      */
327     public void stopServer(String[] arguments)
328         throws Exception {
329 
330         Object param[];
331         Class<?> paramTypes[];
332         if (arguments==null || arguments.length==0) {
333             paramTypes = null;
334             param = null;
335         } else {
336             paramTypes = new Class[1];
337             paramTypes[0] = arguments.getClass();
338             param = new Object[1];
339             param[0] = arguments;
340         }
341         Method method =
342             catalinaDaemon.getClass().getMethod("stopServer", paramTypes);
343         method.invoke(catalinaDaemon, param);
344 
345     }
346 
347 
348     /**
349      * Set flag.
350      */
351     public void setAwait(boolean await)
352         throws Exception {
353 
354         Class<?> paramTypes[] = new Class[1];
355         paramTypes[0] = Boolean.TYPE;
356         Object paramValues[] = new Object[1];
357         paramValues[0] = Boolean.valueOf(await);
358         Method method =
359             catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
360         method.invoke(catalinaDaemon, paramValues);
361 
362     }
363 
364     public boolean getAwait()
365         throws Exception
366     {
367         Class<?> paramTypes[] = new Class[0];
368         Object paramValues[] = new Object[0];
369         Method method =
370             catalinaDaemon.getClass().getMethod("getAwait", paramTypes);
371         Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues);
372         return b.booleanValue();
373     }
374 
375 
376     /**
377      * Destroy the Catalina Daemon.
378      */
379     public void destroy() {
380 
381         // FIXME
382 
383     }
384 
385 
386     /**
387      * Main method and entry point when starting Tomcat via the provided
388      * scripts.
389      *
390      * @param args Command line arguments to be processed
391      */
392     public static void main(String args[]) {
393 
394         if (daemon == null) {
395             // Don‘t set daemon until init() has completed
396             Bootstrap bootstrap = new Bootstrap();
397             try {
398                 bootstrap.init();
399             } catch (Throwable t) {
400                 handleThrowable(t);
401                 t.printStackTrace();
402                 return;
403             }
404             daemon = bootstrap;
405         } else {
406             // When running as a service the call to stop will be on a new
407             // thread so make sure the correct class loader is used to prevent
408             // a range of class not found exceptions.
409             Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
410         }
411 
412         try {
413             String command = "start";
414             if (args.length > 0) {
415                 command = args[args.length - 1];
416             }
417 
418             if (command.equals("startd")) {
419                 args[args.length - 1] = "start";
420                 daemon.load(args);
421                 daemon.start();
422             } else if (command.equals("stopd")) {
423                 args[args.length - 1] = "stop";
424                 daemon.stop();
425             } else if (command.equals("start")) {
426                 daemon.setAwait(true);
427                 daemon.load(args);
428                 daemon.start();
429             } else if (command.equals("stop")) {
430                 daemon.stopServer(args);
431             } else if (command.equals("configtest")) {
432                 daemon.load(args);
433                 if (null==daemon.getServer()) {
434                     System.exit(1);
435                 }
436                 System.exit(0);
437             } else {
438                 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
439             }
440         } catch (Throwable t) {
441             // Unwrap the Exception for clearer error reporting
442             if (t instanceof InvocationTargetException &&
443                     t.getCause() != null) {
444                 t = t.getCause();
445             }
446             handleThrowable(t);
447             t.printStackTrace();
448             System.exit(1);
449         }
450 
451     }
452 
453     public void setCatalinaHome(String s) {
454         System.setProperty(Globals.CATALINA_HOME_PROP, s);
455     }
456 
457     public void setCatalinaBase(String s) {
458         System.setProperty(Globals.CATALINA_BASE_PROP, s);
459     }
460 
461 
462     /**
463      * Set the <code>catalina.base</code> System property to the current
464      * working directory if it has not been set.
465      */
466     private void setCatalinaBase() {
467 
468         if (System.getProperty(Globals.CATALINA_BASE_PROP) != null)
469             return;
470         if (System.getProperty(Globals.CATALINA_HOME_PROP) != null)
471             System.setProperty(Globals.CATALINA_BASE_PROP,
472                                System.getProperty(Globals.CATALINA_HOME_PROP));
473         else
474             System.setProperty(Globals.CATALINA_BASE_PROP,
475                                System.getProperty("user.dir"));
476 
477     }
478 
479 
480     /**
481      * Set the <code>catalina.home</code> System property to the current
482      * working directory if it has not been set.
483      */
484     private void setCatalinaHome() {
485 
486         if (System.getProperty(Globals.CATALINA_HOME_PROP) != null)
487             return;
488         File bootstrapJar =
489             new File(System.getProperty("user.dir"), "bootstrap.jar");
490         if (bootstrapJar.exists()) {
491             try {
492                 System.setProperty
493                     (Globals.CATALINA_HOME_PROP,
494                      (new File(System.getProperty("user.dir"), ".."))
495                      .getCanonicalPath());
496             } catch (Exception e) {
497                 // Ignore
498                 System.setProperty(Globals.CATALINA_HOME_PROP,
499                                    System.getProperty("user.dir"));
500             }
501         } else {
502             System.setProperty(Globals.CATALINA_HOME_PROP,
503                                System.getProperty("user.dir"));
504         }
505 
506     }
507 
508 
509     /**
510      * Get the value of the catalina.home environment variable.
511      */
512     public static String getCatalinaHome() {
513         return System.getProperty(Globals.CATALINA_HOME_PROP,
514                                   System.getProperty("user.dir"));
515     }
516 
517 
518     /**
519      * Get the value of the catalina.base environment variable.
520      */
521     public static String getCatalinaBase() {
522         return System.getProperty(Globals.CATALINA_BASE_PROP, getCatalinaHome());
523     }
524 
525 
526     // Copied from ExceptionUtils since that class is not visible during start
527     private static void handleThrowable(Throwable t) {
528         if (t instanceof ThreadDeath) {
529             throw (ThreadDeath) t;
530         }
531         if (t instanceof VirtualMachineError) {
532             throw (VirtualMachineError) t;
533         }
534         // All other instances of Throwable will be silently swallowed
535     }
536 }
Bootstrap 

 

/*

 * Licensed to the Apache Software Foundation (ASF) under one or more

 * contributor license agreements.  See the NOTICE file distributed with

 * this work for additional information regarding copyright ownership.

 * The ASF licenses this file to You under the Apache License, Version 2.0

 * (the "License"); you may not use this file except in compliance with

 * the License.  You may obtain a copy of the License at

 *

 *      http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */

package org.apache.catalina.startup;

 

import java.io.File;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;

import java.util.StringTokenizer;

 

import org.apache.catalina.Globals;

import org.apache.catalina.security.SecurityClassLoad;

import org.apache.catalina.startup.ClassLoaderFactory.Repository;

import org.apache.catalina.startup.ClassLoaderFactory.RepositoryType;

import org.apache.juli.logging.Log;

import org.apache.juli.logging.LogFactory;

 

/**

 * Bootstrap loader for Catalina.  This application constructs a class loader

 * for use in loading the Catalina internal classes (by accumulating all of the

 * JAR files found in the "server" directory under "catalina.home"), and

 * starts the regular execution of the container.  The purpose of this

 * roundabout approach is to keep the Catalina internal classes (and any

 * other classes they depend on, such as an XML parser) out of the system

 * class path and therefore not visible to application level classes.

 * 

 * @author Craig R. McClanahan

 * @author Remy Maucherat

 */

// Catalina的Bootstrap加载器。这个应用为加载Catalina的内部类(通过累加“catalina.home”下的jar文件)构造了一个类加载器,并启动了容器。

// 这种间接做法的目的是使catalina的内部类(和它依赖的其他类,必须Xml转化器)与系统的class path分离,与应用级别的类互相不能访问。

public final class Bootstrap {

 

    private static final Log log = LogFactory.getLog(Bootstrap.class);

 

 

    // ------------------------------------------------------- Static Variables

 

 

    /**

     * Daemon object used by main.

     */

    private static Bootstrap daemon = null;

 

 

    // -------------------------------------------------------------- Variables

 

 

    /**

     * Daemon reference.

     */

    private Object catalinaDaemon = null;

 

 

    ClassLoader commonLoader = null;

    ClassLoader catalinaLoader = null;

    ClassLoader sharedLoader = null;

 

 

    // -------------------------------------------------------- Private Methods

 

 

    private void initClassLoaders() {

        try {

            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); // 在tomcat 7x的catalina.properties中server.loader为空

            sharedLoader = createClassLoader("shared", commonLoader); // 在tomcat 7x的catalina.properties中shared.loader为空

        } catch (Throwable t) {

            handleThrowable(t);

            log.error("Class loader creation threw exception", t);

            System.exit(1);

        }

    }

 

   // 如果配置文件中没有name+".loader"属性, 返回parent

    private ClassLoader createClassLoader(String name, ClassLoader parent)

        throws Exception {

 

        String value = http://www.mamicode.com/CatalinaProperties.getProperty(name +".loader");

        if ((value =http://www.mamicode.com/= null) || (value.equals("")))

            return parent;

 

        value = http://www.mamicode.com/replace(value); // 替换catalina.home和catalina.base

 

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

 

        StringTokenizer tokenizer = new StringTokenizer(value, ","); // 处理value把结尾不同的值放进不同的Repository

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

            }

        }

 

        return ClassLoaderFactory.createClassLoader(repositories, parent); // 特权化

    }

 

    /**

     * System property replacement in the given string.

     * 

     * @param str The original string

     * @return the modified string

     */

    protected String replace(String str) {

        // Implementation is copied from ClassLoaderLogManager.replace(),

        // but added special processing for catalina.home and catalina.base.

        String result = str;

        int pos_start = str.indexOf("${");

        if (pos_start >= 0) {

            StringBuilder builder = new StringBuilder();

            int pos_end = -1;

            while (pos_start >= 0) {

                builder.append(str, pos_end + 1, pos_start);

                pos_end = str.indexOf(‘}‘, pos_start + 2);

                if (pos_end < 0) {

                    pos_end = pos_start - 1;

                    break;

                }

                String propName = str.substring(pos_start + 2, pos_end);

                String replacement;

                if (propName.length() == 0) {

                    replacement = null;

                } else if (Globals.CATALINA_HOME_PROP.equals(propName)) {

                    replacement = getCatalinaHome();

                } else if (Globals.CATALINA_BASE_PROP.equals(propName)) {

                    replacement = getCatalinaBase();

                } else {

                    replacement = System.getProperty(propName);

                }

                if (replacement != null) {

                    builder.append(replacement);

                } else {

                    builder.append(str, pos_start, pos_end + 1);

                }

                pos_start = str.indexOf("${", pos_end + 1);

            }

            builder.append(str, pos_end + 1, str.length());

            result = builder.toString();

        }

        return result;

    }

 

 

    /**

     * Initialize daemon.

     */

    public void init()

        throws Exception

    {

 

        // Set Catalina path

        setCatalinaHome(); // 设置catalina.home, 在catalina.bat启动Bootstarp.java时通过-Dcatalina.home传入; 没有就重新设置

        setCatalinaBase(); // 设置catalina.base, 在catalina.bat启动Bootstarp.java时通过-Dcatalina.base传入; 没有就重新设置

 

        initClassLoaders(); // 使用catalina.properties初始化了3个ClassLoader, 在tomcat7x中catalina.loader和server.loader为空;

                            // 所以catalinaLoader = commonLoader; sharedLoader = commonLoader;

                            // commonLoader没有parent classLoader, catalinaLoader和sharedLoader的parent classLoader是commonLoader

        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); // 调用Catalina.setParentClassLoader(), sharedLoader作为参数, 参数类型是ClassLoader

 

        catalinaDaemon = startupInstance; // catalina守护进程

 

    }

 

 

    /**

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

        }

        Method method =

            catalinaDaemon.getClass().getMethod(methodName, paramTypes);

        if (log.isDebugEnabled())

            log.debug("Calling startup class " + method);

        method.invoke(catalinaDaemon, param); // catalina.java 下有俩个load方法, 一个有参一个无参

 

    }

 

 

    /**

     * getServer() for configtest

     */

    private Object getServer() throws Exception {

 

        String methodName = "getServer";

        Method method =

            catalinaDaemon.getClass().getMethod(methodName);

        return method.invoke(catalinaDaemon);

 

    }

 

 

    // ----------------------------------------------------------- Main Program

 

 

    /**

     * Load the Catalina daemon.

     */

    public void init(String[] arguments)

        throws Exception {

 

        init();

        load(arguments);

 

    }

 

 

    /**

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

 

    }

 

 

    /**

     * Stop the Catalina Daemon.

     */

    public void stop()

        throws Exception {

 

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

        method.invoke(catalinaDaemon, (Object [] ) null);

 

    }

 

 

    /**

     * Stop the standalone server.

     */

    public void stopServer()

        throws Exception {

 

        Method method =

            catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);

        method.invoke(catalinaDaemon, (Object []) null);

 

    }

 

 

   /**

     * Stop the standalone server.

     */

    public void stopServer(String[] arguments)

        throws Exception {

 

        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;

        }

        Method method =

            catalinaDaemon.getClass().getMethod("stopServer", paramTypes);

        method.invoke(catalinaDaemon, param);

 

    }

 

 

    /**

     * 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] = Boolean.valueOf(await);

        Method method =

            catalinaDaemon.getClass().getMethod("setAwait", paramTypes);

        method.invoke(catalinaDaemon, paramValues);

 

    }

 

    public boolean getAwait()

        throws Exception

    {

        Class<?> paramTypes[] = new Class[0];

        Object paramValues[] = new Object[0];

        Method method =

            catalinaDaemon.getClass().getMethod("getAwait", paramTypes);

        Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues);

        return b.booleanValue();

    }

 

 

    /**

     * Destroy the Catalina Daemon.

     */

    public void destroy() {

 

        // FIXME

 

    }

 

 

    /**

     * Main method and entry point when starting Tomcat via the provided

     * scripts.

     *

     * @param args Command line arguments to be processed

     */

    public static void main(String args[]) {

 

        if (daemon == null) { // stop时不为空

            // Don‘t set daemon until init() has completed

            Bootstrap bootstrap = new Bootstrap();

            try {

                bootstrap.init(); // 执行init()

            } catch (Throwable t) {

                handleThrowable(t);

                t.printStackTrace();

                return;

            }

            daemon = bootstrap; // 守护进程

        } else {

            // When running as a service the call to stop will be on a new

            // thread so make sure the correct class loader is used to prevent

            // a range of class not found exceptions.

            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);

        }

 

        try { // catalina.bat把start作为最后一个参数启动

            String command = "start";

            if (args.length > 0) {

                command = args[args.length - 1];

            }

            // 根据不同参数, 调用catalina.java中的同名方法; command = startd或start或onfigtest时, 先通过反射调用catalina.load方法

            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.");

            }

        } catch (Throwable t) {

            // Unwrap the Exception for clearer error reporting

            if (t instanceof InvocationTargetException &&

                    t.getCause() != null) {

                t = t.getCause();

            }

            handleThrowable(t);

            t.printStackTrace();

            System.exit(1);

        }

 

    }

 

    public void setCatalinaHome(String s) {

        System.setProperty(Globals.CATALINA_HOME_PROP, s);

    }

 

    public void setCatalinaBase(String s) {

        System.setProperty(Globals.CATALINA_BASE_PROP, s);

    }

 

 

    /**

     * Set the <code>catalina.base</code> System property to the current

     * working directory if it has not been set.

     */

    private void setCatalinaBase() {

 

        if (System.getProperty(Globals.CATALINA_BASE_PROP) != null)

            return;

        if (System.getProperty(Globals.CATALINA_HOME_PROP) != null)

            System.setProperty(Globals.CATALINA_BASE_PROP,

                               System.getProperty(Globals.CATALINA_HOME_PROP));

        else

            System.setProperty(Globals.CATALINA_BASE_PROP,

                               System.getProperty("user.dir"));

 

    }

 

 

    /**

     * Set the <code>catalina.home</code> System property to the current

     * working directory if it has not been set.

     */

    private void setCatalinaHome() {

 

        if (System.getProperty(Globals.CATALINA_HOME_PROP) != null)

            return;

        File bootstrapJar =

            new File(System.getProperty("user.dir"), "bootstrap.jar");

        if (bootstrapJar.exists()) {

            try {

                System.setProperty // 设置catalina.home为user.dir的父目录

                    (Globals.CATALINA_HOME_PROP,

                     (new File(System.getProperty("user.dir"), ".."))

                     .getCanonicalPath());

            } catch (Exception e) {

                // Ignore

                System.setProperty(Globals.CATALINA_HOME_PROP,

                                   System.getProperty("user.dir"));

            }

        } else {

            System.setProperty(Globals.CATALINA_HOME_PROP,

                               System.getProperty("user.dir"));

        }

 

    }

 

 

    /**

     * Get the value of the catalina.home environment variable.

     */

    public static String getCatalinaHome() {

        return System.getProperty(Globals.CATALINA_HOME_PROP,

                                  System.getProperty("user.dir"));

    }

 

 

    /**

     * Get the value of the catalina.base environment variable.

     */

    public static String getCatalinaBase() {

        return System.getProperty(Globals.CATALINA_BASE_PROP, getCatalinaHome());

    }

 

 

    // Copied from ExceptionUtils since that class is not visible during start

    private static void handleThrowable(Throwable t) {

        if (t instanceof ThreadDeath) {

            throw (ThreadDeath) t;

        }

        if (t instanceof VirtualMachineError) {

            throw (VirtualMachineError) t;

        }

        // All other instances of Throwable will be silently swallowed

    }

}

 

(三)Bootstrap.jar