How tomcat works——17 启动Tomcat

概述

本章关注的重点是如何使用 org.apache.catalina.startup下面的Catalina和 Bootstrap 类来启动Tomcat。Catalina类用于解析Tomcat配置文件server.xml以及启动和停止Server。Bootstrap 类创建一Catalina实例并调用它的 process()方法。理论上,这两个类可以合成一个类。但是,为了支持 Tomcat 的多模式启动,提供了多个引导类。例如前述的 Bootstrap 类是将 Tomcat 作为一个独立的程序运行,而org.apache.catalina.startup.BootstrapService 则是将 Tomcat 作为一个Windows NT 系统的服务来运行。

为了使用方便,Tomcat 提供了批处理文件及Shell 脚本来启动和停止servlet 容器。有了这些批处理文件和 Shell 脚本的帮助,用户则就不需要记住java.exe 的选项来运行 Bootstrap 类,简单地运行批处理文件或Shell 脚本即可。

本章第1节讨论 Catalina 类,第2节讨论 Bootstrap 类。要理解本章内容,首先要确保已经读过 14、15、16 章的内容。本章还讨论了如何在 Windows 以及 Unix/Linux 下面运行 Tomcat。一节介绍 Windows 环境下的批处理文件,一节介绍 Unix/Linux 下面的 Shell 脚本。

17.1 Catalina类

org.apache.catalina.startup.Catalina 是 Tomcat 的启动类。它包含一个用于解析%CATALINE_HOME%/conf 目录下面 server.xml配置文件的 Digester。通过理解添加到此Digester的规则,我们可以按需配置Tomcat。

Catalina 类还封装了一个 Server 对象用来提供服务。如第 15 章所介绍,一个Service对象包括一个容器以及一个或多个连接器。我们可以使用Catalina 来启动或停止 Server 对象。

可以首先初始化一个 Catalina 对象并调用它的 process()方法来启动 Tomcat,在调用该方法时必须传递合适的参数。如果要启动Tomcat,则第一个参数为startl;如果关闭,则发送shutdown命令停止它。 还有其它可接受的命令,如-help,-config,-debug和-nonaming。

注意:nonaming 参数出现时,说明不支持 JNDI 命名空间。有关更多的 Tomcat 对于 JNDI 命名空间的支持请看 org.apache.naming 包。

通常,需要 Bootstrap 类来初始化 Catalina 对象并调用它的 process()方法,即使 Catalina 有自己的 main()方法。下一节里将会介绍Bootstrap类,本节也会对它是如何工作的略做介绍。

Tomcat4 中的 process ()方法如 Listing17.1 所示:

Listing 17.1: The process method of the Catalina class

public void process(String args[]) {
    setCatalinaHome();
    setCatalinaBase();
    try {
        if (arguments(args))
        execute();
    }catch (Exception e) {
        e.printStackTrace(System.out);
    }
}

该方法设置2个系统属性 catalina.home 和 catalina.base,catalina.home默认值是 user.dir 属性的值。Catalina.base 被设置为 catalina.home 的值。因此这2个属性的值都跟 user.dir 属性值相同。

注意:user.dir 系统属性是指当前用户工作空间,即运行 Java 命令的目录。可以通过java.lang.System 中getProperties()获取到系统属性列表。

然后 process()方法调用了arguments()方法,如Listing17.2。该方法处理参数列表,如果 Catalina 对象能继续工作则返回 true。

Listing 17.2: The arguments method

protected boolean arguments(String args[]) {

        boolean isConfig = false;

        if (args.length < 1) {
            usage();
            return (false);
        }

        for (int i = 0; i < args.length; i++) {
            if (isConfig) {
                configFile = args[i];
                isConfig = false;
            } else if (args[i].equals("-config")) {
                isConfig = true;
            } else if (args[i].equals("-debug")) {
                debug = true;
            } else if (args[i].equals("-nonaming")) {
                useNaming = false;
            } else if (args[i].equals("-help")) {
                usage();
                return (false);
            } else if (args[i].equals("start")) {
                starting = true;
            } else if (args[i].equals("stop")) {
                stopping = true;
            } else {
                usage();
                return (false);
            }
        }

        return (true);

    }

process()方法检查 arguments()方法的返回值,如果为 true 就调用 execute()方法。该方法如 Listing17.3 所示:

Listing 17.3: The execute method

protected void execute() throws Exception {
    if (starting)
        start();
    else if (stopping)
        stop();
}

方法execute()用于调用 start()或stop() 方法来启动或者停止 Tomcat。这2个方法将在下面的子章节中介绍。

注意:在 Tomcat5 中,没有 execute() 方法,process()方法直接调用 start() 方法和stop()方法。

17.1.1 start()方法

start()方法创建一个 Digester 实例来处理 server.xml 文件(Tomcat 的配置文件)。在解析 XML 文件之前,start()方法调用Digester 的 push()方法,传递当前Catalina 对象。这意味着Catalina 对象是Digester内部堆栈中第1个对象。解析文件可以设置Server对象的变量,Server默认类型是org.apache.catalina.core.StandardServer。然后 start()方法调用Server对象的 initialize()和start()方法。然后再调用Server的await()方法,服务器分配一个线程等待停止命令。该方法不返回,直到收到停止命令。当 await()方法返回后,则继续调用Server对象的 stop()方法用于停止服务器以及所有组件。start()方法也采用了关闭钩子的方法以此确保Server对象的 stop()方法即使在用户突然退出该应用程序情况下也总会执行。start()方法如 Listing17.4 所示。

Listing 17.4: The start method

protected void start() {

        // Create and execute our Digester
        Digester digester = createStartDigester();
        File file = configFile();
        try {
            InputSource is =
                new InputSource("file://" + file.getAbsolutePath());
            FileInputStream fis = new FileInputStream(file);
            is.setByteStream(fis);
            digester.push(this);
            digester.parse(is);
            fis.close();
        } catch (Exception e) {
            System.out.println("Catalina.start: " + e);
            e.printStackTrace(System.out);
            System.exit(1);
        }

        // Setting additional variables
        if (!useNaming) {
            System.setProperty("catalina.useNaming", "false");
        } else {
            System.setProperty("catalina.useNaming", "true");
            String value = "org.apache.naming";
            String oldValue =
                System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);
            if (oldValue != null) {
                value = value + ":" + oldValue;
            }
            System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);
            value = System.getProperty
                (javax.naming.Context.INITIAL_CONTEXT_FACTORY);
            if (value == null) {
                System.setProperty
                    (javax.naming.Context.INITIAL_CONTEXT_FACTORY,
                     "org.apache.naming.java.javaURLContextFactory");
            }
        }

        // If a SecurityManager is being used, set properties for
        // checkPackageAccess() and checkPackageDefinition
        if( System.getSecurityManager() != null ) {
            String access = Security.getProperty("package.access");
            if( access != null && access.length() > 0 )
                access += ",";
            else
                access = "sun.,";
            Security.setProperty("package.access",
                access + "org.apache.catalina.,org.apache.jasper.");
            String definition = Security.getProperty("package.definition");
            if( definition != null && definition.length() > 0 )
                definition += ",";
            else
                definition = "sun.,";
            Security.setProperty("package.definition",
                // FIX ME package "javax." was removed to prevent HotSpot
                // fatal internal errors
                definition + "java.,org.apache.catalina.,org.apache.jasper.");
        }

        // Replace System.out and System.err with a custom PrintStream
        SystemLogHandler log = new SystemLogHandler(System.out);
        System.setOut(log);
        System.setErr(log);

        Thread shutdownHook = new CatalinaShutdownHook();

        // Start the new server
        if (server instanceof Lifecycle) {
            try {
                server.initialize();
                ((Lifecycle) server).start();
                try {
                    // Register shutdown hook
                    Runtime.getRuntime().addShutdownHook(shutdownHook);
                } catch (Throwable t) {
                    // This will fail on JDK 1.2. Ignoring, as Tomcat can run
                    // fine without the shutdown hook.
                }
                // Wait for the server to be told to shut down
                server.await();
            } catch (LifecycleException e) {
                System.out.println("Catalina.start: " + e);
                e.printStackTrace(System.out);
                if (e.getThrowable() != null) {
                    System.out.println("----- Root Cause -----");
                    e.getThrowable().printStackTrace(System.out);
                }
            }
        }

        // Shut down the server
        if (server instanceof Lifecycle) {
            try {
                try {
                    // Remove the ShutdownHook first so that server.stop()
                    // doesn't get invoked twice
                    Runtime.getRuntime().removeShutdownHook(shutdownHook);
                } catch (Throwable t) {
                    // This will fail on JDK 1.2. Ignoring, as Tomcat can run
                    // fine without the shutdown hook.
                }
                ((Lifecycle) server).stop();
            } catch (LifecycleException e) {
                System.out.println("Catalina.stop: " + e);
                e.printStackTrace(System.out);
                if (e.getThrowable() != null) {
                    System.out.println("----- Root Cause -----");
                    e.getThrowable().printStackTrace(System.out);
                }
            }
        }

    }

17.1.2 stop()方法

stop()方法用于关闭 Catalina 并且关闭 Server 对象。Stop 方法如 Listing17.5所示。

Listing 17.5: The stop Method

protected void stop() {

        // Create and execute our Digester
        Digester digester = createStopDigester();
        File file = configFile();
        try {
            InputSource is =
                new InputSource("file://" + file.getAbsolutePath());
            FileInputStream fis = new FileInputStream(file);
            is.setByteStream(fis);
            digester.push(this);
            digester.parse(is);
            fis.close();
        } catch (Exception e) {
            System.out.println("Catalina.stop: " + e);
            e.printStackTrace(System.out);
            System.exit(1);
        }

      // Stop the existing server
      try {
          Socket socket = new Socket("127.0.0.1", server.getPort());
          OutputStream stream = socket.getOutputStream();
          String shutdown = server.getShutdown();
          for (int i = 0; i < shutdown.length(); i++)
              stream.write(shutdown.charAt(i));
          stream.flush();
          stream.close();
          socket.close();
      } catch (IOException e) {
          System.out.println("Catalina.stop: " + e);
          e.printStackTrace(System.out);
          System.exit(1);
      }


    }

注意stop()方法通过 createStopDigester()方法创建了一个 Digester 实例。把当前Catalina 对象压入到 Digester 内部栈中,并解析其配置文件,Digester 的规则添加将在下一小节中介绍。

在收到关闭命令后,stop()方法则停止服务器。

17.1.3 启动Digester

Catalina 的 createStartDigester()用于创建 Digester 实例然后向其添加规则来解析 server.xml。该文件用于配置Tomcat,位于%CATALINE_HOME%/conf 目录下面。向 Digester 添加的规则是理解 Tomcat 配置的关键。createStartDigester()方法如 Listing17.6 所示。

Listing 17.6: The createStartDigester method

protected Digester createStartDigester() {

        // Initialize the digester
        Digester digester = new Digester();
        if (debug)
            digester.setDebug(999);
        digester.setValidating(false);

        // Configure the actions we will be using
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

        digester.addObjectCreate("Server/GlobalNamingResources",
                                 "org.apache.catalina.deploy.NamingResources");
        digester.addSetProperties("Server/GlobalNamingResources");
        digester.addSetNext("Server/GlobalNamingResources",
                            "setGlobalNamingResources",
                            "org.apache.catalina.deploy.NamingResources");

        digester.addObjectCreate("Server/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Listener");
        digester.addSetNext("Server/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");

        digester.addObjectCreate("Server/Service/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Listener");
        digester.addSetNext("Server/Service/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        digester.addObjectCreate("Server/Service/Connector",
                                 "org.apache.catalina.connector.http.HttpConnector",
                                 "className");
        digester.addSetProperties("Server/Service/Connector");
        digester.addSetNext("Server/Service/Connector",
                            "addConnector",
                            "org.apache.catalina.Connector");

        digester.addObjectCreate("Server/Service/Connector/Factory",
                                 "org.apache.catalina.net.DefaultServerSocketFactory",
                                 "className");
        digester.addSetProperties("Server/Service/Connector/Factory");
        digester.addSetNext("Server/Service/Connector/Factory",
                            "setFactory",
                            "org.apache.catalina.net.ServerSocketFactory");

        digester.addObjectCreate("Server/Service/Connector/Listener",
                                 null, // MUST be specified in the element
                                 "className");
        digester.addSetProperties("Server/Service/Connector/Listener");
        digester.addSetNext("Server/Service/Connector/Listener",
                            "addLifecycleListener",
                            "org.apache.catalina.LifecycleListener");

        // Add RuleSets for nested elements
        digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Default"));
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/DefaultContext/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/Default"));
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/DefaultContext/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
        digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));

        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(digester,
                                                      parentClassLoader));


        return (digester);

    }

createStartDigester()方法创建一个 org.apache.commons.digester.Digester类的实例,然后添加规则。

在 server.xml 中的前三个规则是针对 server 元素的,server 元素是根元素,如下是 server 模式的规则:

digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer", "className");
digester.addSetProperties("Server");
digester.addSetNext("Server", "setServer","org.apache.catalina.Server");

在遇到 server 元素时,Digester 要创建org.apache.catalina.core.StandardServer 的实例。一种例外是 server 元素配置了className 属性,此时它表示是要被初始化的类。

第二个规则使用具有相同名称的元素属性的值来填充Server对象的属性。

第三条规则将 Server 对象压入堆栈并将其与下一个对象(Catalina 对象)相关联,使用的方法是 setServer()方法。是如何将一个 Catalina 的对象放入 Digester的栈中的?在start()方法中调用Digester的push()方法来解析server.xml:

digester.push (this);

上面的代码将 Catalina 对象压入 Digester 的内部栈中。

其余的规则可以根据方法中的代码得出,如果有困难,请重读 第15 章。

17.1.4 停止Digester

createStopDigester()方法返回一个 Digester 对象用于优雅地停止服务器对象,该方法如 Listing17.7所示。

Listing 17.7: The stop method

protected Digester createStopDigester() {

        // Initialize the digester
        Digester digester = new Digester();
        if (debug)
            digester.setDebug(999);

        // Configure the rules we need for shutting down
        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

        return (digester);

    }

跟开始 Digester 不同,停止 Digester 仅仅对根元素感兴趣。

17.2 Bootstrap类

org.apache.catalina.startup.Bootstrap 类提供了 Tomcat 的启动入口。当运行 startup.bat 或 startup.sh 时,实际上运行的就是该类中的main()方法。该方法创建3个类加载器并初始化 Catalina 类,然后调用 Catalina 的process()方法。

Bootstrap 类如 Listing17.8 所示:

package org.apache.catalina.startup;

import java.io.File;
import java.lang.reflect.Method;


/**
 * Boostrap 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
 * @version $Revision: 1.36 $ $Date: 2002/04/01 19:51:31 $
 */

public final class Bootstrap {


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


    /**
     * Debugging detail level for processing the startup.
     */
    private static int debug = 0;


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


    /**
     * The main program for the bootstrap.
     *
     * @param args Command line arguments to be processed
     */
    public static void main(String args[]) {

        // Set the debug flag appropriately
        for (int i = 0; i < args.length; i++)  {
            if ("-debug".equals(args[i]))
                debug = 1;
        }

        // Configure catalina.base from catalina.home if not yet set
        if (System.getProperty("catalina.base") == null)
            System.setProperty("catalina.base", getCatalinaHome());

        // Construct the class loaders we will need
        ClassLoader commonLoader = null;
        ClassLoader catalinaLoader = null;
        ClassLoader sharedLoader = null;
        try {

            File unpacked[] = new File[1];
            File packed[] = new File[1];
            File packed2[] = new File[2];
            ClassLoaderFactory.setDebug(debug);

            unpacked[0] = new File(getCatalinaHome(),
                                   "common" + File.separator + "classes");
            packed2[0] = new File(getCatalinaHome(),
                                  "common" + File.separator + "endorsed");
            packed2[1] = new File(getCatalinaHome(),
                                  "common" + File.separator + "lib");
            commonLoader =
                ClassLoaderFactory.createClassLoader(unpacked, packed2, null);

            unpacked[0] = new File(getCatalinaHome(),
                                   "server" + File.separator + "classes");
            packed[0] = new File(getCatalinaHome(),
                                 "server" + File.separator + "lib");
            catalinaLoader =
                ClassLoaderFactory.createClassLoader(unpacked, packed,
                                                     commonLoader);

            unpacked[0] = new File(getCatalinaBase(),
                                   "shared" + File.separator + "classes");
            packed[0] = new File(getCatalinaBase(),
                                 "shared" + File.separator + "lib");
            sharedLoader =
                ClassLoaderFactory.createClassLoader(unpacked, packed,
                                                     commonLoader);
        } catch (Throwable t) {

            log("Class loader creation threw exception", t);
            System.exit(1);

        }

        Thread.currentThread().setContextClassLoader(catalinaLoader);

        // Load our startup class and call its process() method
        try {

            SecurityClassLoad.securityClassLoad(catalinaLoader);

            // Instantiate a startup class instance
            if (debug >= 1)
                log("Loading startup class");
            Class startupClass =
                catalinaLoader.loadClass
                ("org.apache.catalina.startup.Catalina");
            Object startupInstance = startupClass.newInstance();

            // Set the shared extensions class loader
            if (debug >= 1)
                log("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);

            // Call the process() method
            if (debug >= 1)
                log("Calling startup class process() method");
            methodName = "process";
            paramTypes = new Class[1];
            paramTypes[0] = args.getClass();
            paramValues = new Object[1];
            paramValues[0] = args;
            method =
                startupInstance.getClass().getMethod(methodName, paramTypes);
            method.invoke(startupInstance, paramValues);

        } catch (Exception e) {
            System.out.println("Exception during startup processing");
            e.printStackTrace(System.out);
            System.exit(2);
        }

    }


    /**
     * Get the value of the catalina.home environment variable.
     */
    private static String getCatalinaHome() {
        return System.getProperty("catalina.home",
                                  System.getProperty("user.dir"));
    }


    /**
     * Get the value of the catalina.base environment variable.
     */
    private static String getCatalinaBase() {
        return System.getProperty("catalina.base", getCatalinaHome());
    }


    /**
     * Log a debugging detail message.
     *
     * @param message The message to be logged
     */
    private static void log(String message) {

        System.out.print("Bootstrap: ");
        System.out.println(message);

    }


    /**
     * Log a debugging detail message with an exception.
     *
     * @param message The message to be logged
     * @param exception The exception to be logged
     */
    private static void log(String message, Throwable exception) {

        log(message);
        exception.printStackTrace(System.out);

    }

}

Bootstrap 类有4个静态方法:2个 log 方法、getCatalinaHome()以及getCatalinaBase()方法。getCatalinaHome()方法的实现如下:

return System.getProperty("catalina.home",System.getProperty("user.dir"));

它意味着如果在前面没有提供 catalina.home 的值,它会使用 user.dir 的值。

getCatalinaBase()方法的实现如下:

return System.getProperty("catalina.base", getCatalinaHome());

它返回 catalina.base 的值,如果该值不存在则返回 catalina.home 的值。

getCatalinaHome() 和 getCatalinaBase() 都会被 Bootstrap 类的main()方法调用。

Bootstrap 类中main()方法还构造了3个用于不同用处的加载器。拥有不同类加载器的主要原因是阻止应用程序类(Web应用程序中的servlet和其它帮助类)在WEB-INF/classes和WEB-INF/lib目录之外运行类。部署到%CATALINE_HOME%/common/lib目录的Jar包也是被允许的。

这3个类加载器定义如下:

// Construct the class loaders we will need
ClassLoader commonLoader = null;
ClassLoader catalinaLoader = null;
ClassLoader sharedLoader = null;

每个类加载器都给定一个可以访问的路径。commonLoader 可以访问如下3个目录下的类:%CATALINA_HOME%/common/classes,%CATALINA_HOME%/common/endorsed
和 %CATALINA_HOME%/common/lib。

try {
    File unpacked[] = new File[1];
    File packed[] = new File[1];
    File packed2[] = new File[2];
    ClassLoaderFactory.setDebug(debug);
    unpacked[0] = new File(getCatalinaHome(),"common" + File.separator + "classes");
    packed2[0] = new File(getCatalinaHome(),"common" + File.separator + "endorsed");
    packed2[1] = new File(getCatalinaHome(),"common" + File.separator + "lib");
    commonLoader =ClassLoaderFactory.createClassLoader(unpacked, packed2, null);

catalinaLoader 负责加载 Catalina 容器需要的类,它可以加载%CATALINA_HOME%/server/classes 和%CATALINA_HOME%/server/lib 目录下面的类。以及commonLoader类加载器可以访问的所有目录。

unpacked[0] = new File(getCatalinaHome(),"server" + File.separator + "classes");
packed[0] = new File(getCatalinaHome(),"server" + File.separator + "lib");
catalinaLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);

sharedLoader 可以访问%CATALINA_HOME%/shared/classes和%CATALJNA_HOME%/shared/lib 目录下的类以及 commondLoader 类可以访问的类。然后将sharedLoader类加载器分配为部署在Tomcat中该上下文相关联的每个Web应用程序的每个类加载器的父类加载器。

    unpacked[0] = new File(getCatalinaBase(),"shared" + File.separator + "classes");
    packed[0] = new File(getCatalinaBase(),"shared" + File.separator + "lib");
    sharedLoader =ClassLoaderFactory.createClassLoader(unpacked, packed,commonLoader);
}catch (Throwable t) {
    log('Class loader creation threw exception", t);
    System.exit(1);
}

请注意,sharedLoader类加载器无法访问Catalina内部类和CLASSPATH环境中定义的类路径变量。可以在第8章看到更多的加载器工作原理。

创建完3个类加载器后,加载了 Catalina 类并创建它的实例并将其赋值给 startupInstance 变量:

Class startupClass =catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();

然后调用 setParentClassLoader()方法,将 sharedLoader 作为参数:

// Set the shared extensions class loader
if (debug >= 1)
    log("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 对象的 process ()方法:

// Call the process() method
if (debug >= 1)
    log("Calling startup class process() method");
methodName = "process";
paramTypes = new Class[1];
paramTypes[0] = args.getClass();
paramValues = new Object[1];
paramValues[0] = args;
method = startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);

17.3 Windows平台运行Tomcat

如在前面的小节中介绍的,可以使用 Bootstrap 类将 Tomcat 作为一个独立程序运行。在 Windows 平台下,可以使用 starup.bat和 shutdown.bat来启动、停止Tomcat。这两个批处理文件都在%CATALINA_HOME%/bin 目录下。本节主要讨论批处理文件,对于不熟悉 DOS命令的,首先阅读“批处理文件简介”小节。

17.3.1 批处理文件简介

本节主要介绍批处理文件,这样就能理解用于启动和停止 Tomcat 的批处理文件。尤其,解释了如下命令:rem, if, echo, goto, label 等。这里并没有做全面介绍,如果需要更多内容可以查阅其它资源。

首先,一个批处理文件的扩展名必须为.bat。可以双击启动或在DOS控制台命令行中调用它。一旦被调用,会从头至尾一行行的执行。在Tomcat的批处理文件中用到的元素会在下面介绍到。

注意:DOS 命令和环境变量不区分大小写。

rem:

命令 rem 用作注释,rem 开头的行会被忽略不做处理。

pause:

命令 pause 暂停批处理文件处理并要求用户按键,用户按键后会继续执行。

echo:

该命令将它后面的文本显示到 DOS 控制台上面。例如,下面的语句打印 Hello World 到控制台上并暂停。需要 pause 命令的原因是这样才能看到控制台上显示的信息:

echo Hello World
pause

要打印出一个环境变量的值,需要使用%将该变量括起来。例如,下面的命令打印出 myVar 的值:echo %myVar%

要打印出操作系统的名字,可以使用如下命令:echo %OS%

echo off:

echo off 防止批处理文件中的命令被显示,只显示执行结果。但是 echo off 命令仍然会显示,要禁止 echo off 命令可以使用@echo off。

@echo off:

@echo off 跟 echo off 相似,但是它也禁止 echo off 命令本身。

set:

该命令用于设置用户定义的或环境变量。设置的变量值临时存放在内存中,在处理完成后被抛弃。例如,下面的命令创建一个名为 THE_KING 的环境变量,值为 Elvis 并将其显示
在控制台上:

set THE_KING=Elvis
echo %THE_KING%
pause

注意:要引用变量的值,使用%符号将变量名括起来。例如,echo %the_king%表示显示 THE_KING 的值。

label:

使用冒号来表示一个标签,你可以将标签传递给 goto 命令,让处理过程跳到该标签处。下面是一个名为 end 的标签:end。接下来看 goto 命令使用。

goto:

命令 goto 强制批处理文件跳到标签定义的行,看下面的例子:

echo Start
goto end
echo I can guarantee this line will not be executed
:end
echo End
pause

在第一行打印出 Start 之后,批处理文件执行 goto 命令,这样控制器跳到 end标签。第三行被跳过。

if:

if 用于测试,它有如下三种使用方式
1. 测试一个变量的值
2. 测试文件的存在性
3. 测试错误值

要测试一个变量的值,使用如下的格式:

if variable==value nextCommand

例如,如下的语句测试 myVar 的值是不是 3。如果是则打印Correct 到控制台上:

set myVar=3
if %myVar%==3 echo Correct

运行上面的命令会测试 myVar 的值并打印出 Correct。

要测试一个文件是否存在,可以使用如下格式:

if exist c:\temp\myFile.txt goto start

如果在 c:\temp 目录中存在 myFile.txt 文件,控制器会跳到 start 标签。

也可以使用 not 关键字来对一个表达式取反。

not:

关键字 not 用于对一个表达式取反,例如,如下命令在 myVar 的值不等于 3 时打印出 Correct:

set myVar=3
if not %myVar%==3 echo Correct
pause

如下命令在 c:\temp 目录中不存在 myFile.txt 文件时跳到 end 标签:

if not exist c:\temp\myFile.txt goto end

exist:

关键字 exist 跟 if 语句连接用于测试一个文件是否存在,参考 if 语句的例子。

接收参数:

可以给批处理文件传递参数,可以使用%1 引用第一个参数,%2 引用第二个参数。依次类推。例如,如下命令打印第一个参数到控制台上:echo %1

如果批处理文件的名字为 test.bat,可以使用 test Hello 命令来调用它,这样就会在控制台上显示 Hello。

下面的批处理文件检查第一个参数,如果是 start,就打印出 Starting application。如果是 stop 就打印出 Stopping application。其它情况打印出:Invalid parameter。

echo off
if %1==start goto start
if %1==stop goto stop
goto invalid
:start
echo Starting application
goto end
:stop
echo Stopping application
goto end
:invalid
echo Invalid parameter
:end

可以用“%1”与空字符串比较来检查批处理文件是否有第一个参数,如果没有则打印出 No parameter:

if "%1"=="" echo No parameter

上面的语句跟下面的相同:

if ""%1""=="""" echo No parameter

shift:

命令 shift 向后移动参数,意味这%2 指向%1,%3 指向%2,依次类推。例如下面的批处理文件使用了 shift 命令:

echo off
shift
echo %1
echo %2

如果运行该命令的时候传递 3 个参数 a、b、c,会获得如下输出:

b
c

第一个参数可以使用%0 引用,最后一个参数丢失。

call:

命令 call 用于调用另一个命令。

setLocal:

可以使用 setLocal 命令来指明对于环境变量的改变为本地修改。环境变量的值会在执行完文件或碰到 endLocal 命令后恢复。

start:

打开一个新的窗口,可以使用 start 命令,可以传递个参数作为窗口的标题:start “Title”
另外,可以传递给该窗口要执行的命令,格式如下:start “Title” commandName

17.3.2 catalina.bat批处理文件

catalina.bat 文件可以用于启动和停止 Tomcat。但用 startup.bat 和shutdown.bat 可更简便地启动和停止 Tomcat,这两个批处理文件都是通过传递合适的参数给 catalina.bat 文件来实现的。

必须在%CATALINA_HOME%下的 bin目录下面使用如下命令来调用 catalina.bat:

catalina  command

或者在%CATALINA_HOME%目录下使用如下命令:

bin/catalina  command

这两种情况下,可以传递的值如下:
•debug. 在debugger模式下启动
•debug -security. 安全模式调试
•embedded.嵌入式启动
•jpda start.在JPDA 模式下启动调试
•run. 在当前窗口启动
•run -security. 在当前窗口安全模式下启动
•start.独立窗口启动
•start -security. 独立窗口安全模式启动
•stop. 停止

例如,要在一个独立的窗口运行 Catalina,可以使用命令:catalina start

Catalina.bat 如 Listing17.9 所示:

Listing 17.9: The catalina.bat File

@echo off
if "%OS%" == "Windows_NT" setlocal
rem
---------------------------------------------------------------------------
rem Start/Stop Script for the CATALINA Server
rem
rem Environment Variable Prequisites
rem
rem CATALINA_HOME May point at your Catalina "build" directory.
rem
rem CATALINA_BASE (Optional) Base directory for resolving dynamic
portions
rem of a Catalina installation. If not present,
resolves to
rem the same directory that CATALINA_HOME points to.
rem
rem CATALINA_OPTS (Optional) Java runtime options used when the
"start",
rem "stop", or "run" command is executed.
rem
rem CATALINA_TMPDIR (Optional) Directory path location of temporary
directory
rem the JVM should use (java.io.tmpdir). Defaults to
rem %CATALINA_BASE%\temp.
rem
rem JAVA_HOME Must point at your Java Development Kit
installation.
rem
rem JAVA_OPTS (Optional) Java runtime options used when the
"start",
rem "stop", or "run" command is executed.
rem
rem JSSE_HOME (Optional) May point at your Java Secure Sockets
Extension
rem (JSSE) installation, whose JAR files will be
added to the
rem system class path used to start Tomcat.
rem
rem JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda
start"
rem command is executed. The default is "dt_shmem".
rem
rem JPDA_ADDRESS (Optional) Java runtime options used when the
"jpda start"
rem command is executed. The default is "jdbconn".
rem
rem $Id: catalina.bat,v 1.3 2002/08/04 18:19:43 patrickl Exp $
rem
---------------------------------------------------------------------------
rem Guess CATALINA_HOME if not defined
if not "%CATALINA_HOME%" == "" goto gotHome
set CATALINA_HOME=.
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
set CATALINA_HOME=..
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
rem Get standard environment variables
if exist "%CATALINA_HOME%\bin\setenv.bat" call
"%CATALINA_HOME%\bin\setenv.bat"
rem Get standard Java environment variables
if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath
echo Cannot find %CATALINA_HOME%\bin\setclasspath.bat
echo This file is needed to run this program
goto end
:okSetclasspath
set BASEDIR=%CATALINA_HOME%
call "%CATALINA_HOME%\bin\setclasspath.bat"
rem Add on extra jar files to CLASSPATH
if "%JSSE_HOME%" == "" goto noJsse
set
CLASSPATH=%CLASSPATH%;%JSSE_HOME%\lib\jcert.jar;%JSSE_HOME%\lib\jnet.
ja
r;%JSSE_HOME%\lib\jsse.jar
:noJsse
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\bootstrap.jar
if not "%CATALINA_BASE%" == "" goto gotBase
set CATALINA_BASE=%CATALINA_HOME%
:gotBase
if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set CATALINA_TMPDIR=%CATALINA_BASE%\temp
:gotTmpdir
rem ----- Execute The Requested Command ---------------------------------------
echo Using CATALINA_BASE: %CATALINA_BASE%
echo Using CATALINA_HOME: %CATALINA_HOME%
echo Using CATALINA_TMPDIR: %CATALINA_TMPDIR%
echo Using JAVA_HOME: %JAVA_HOME%
set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBOG_OPTS=
set JPDA=
if not ""%1"" == ""jpda"" goto noJpda
set JPDA=jpda
if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
set JPDA_TRANSPORT=dt_shmem
:gotJpdaTransport
if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
set JPDA_ADDRESS=jdbconn
:gotJpdaAddress
shift
:noJpda
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""embedded"" goto doEmbedded
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop
echo Usage: catalina ( commands ... )
echo commands:
echo debug Start Catalina in a debugger
echo debug -security Debug Catalina with a security manager
echo embedded Start Catalina in embedded mode
echo jpda start Start Catalina under JPDA debugger
echo run Start Catalina in the current window
echo run -security Start in the current window with security
manager
echo start Start Catalina in a separate window
echo start -security Start in a separate window with security
manager
echo stop Stop Catalina
goto end
:doDebug
shift
set _EXECJAVA=%_RUNJDB%
set DEBUG_OPTS=-sourcepath "%CATALINA_HOME%\..\..\jakarta-tomcat-
4.0\catalina\src\share"
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy
goto execCmd
:doEmbedded
shift
set MAINCLASS=org.apache.catalina.startup.Embedded
goto execCmd
:doRun
shift
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy
goto execCmd
:doStart
shift
if not "%OS%" == "Windows_NT" goto noTitle
set _EXECJAVA=start "Tomcat" %_RUNJAVA%
goto gotTitle
:noTitle
set _EXECJAVA=start %_RUNJAVA%
:gotTitle
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy
goto execCmd
:doStop
shift
set ACTION=stop
goto execCmd
:execCmd
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
rem Execute Java with the applicable properties
if not "%JPDA%" == "" goto dojpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -
Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -
Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -
Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS%
%ACTION%
goto end
:doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -
Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -
Djava.security.manager
-Djava.security.policy=="%SECURITY_POLICY_FILE%"
-Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -
Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS%
%ACTION%
goto end
:doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% -Xdebug -
Xrunjdwp:transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,s
us
pend=n %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -
classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE%" -
Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%"
%MAINCLASS% %CMD_LINE_ARGS% %ACTION%
goto end
:doSecurityJpda
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% -
Xrunjdwp:transport=%JPDA_TRANSPORT%,address=%JPDA_ADDRESS%,server=y,s
us
pend=n %DEBUG_OPTS% -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -
classpath "%CLASSPATH%" -Djava.security.manager -
Djava.security.policy=="%SECURITY_POLICY_FILE%" -
Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -
Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS%
%ACTION%
goto end
:end

catalina.bat 首先使用@echo off 来避免打印出命令。然后检查 OS 的环境变量的值是否是 Windows_NT。如果是则调用 setLocal 来将环境变量的改变都设置为本地的:

if "%OS%" == "Windows_NT" setlocal

然后设置 CATALINA_HOME 的值,默认情况下该变量是不存在的。如果 CATALINA_HOME 变量值不存在,则就把当前批处理文件所在的目录作为其值。首先它认为catalina.bat 文件是运行在安装目录下,即catalina.bat 所在的 bin 目录:

if not "%CATALINA_HOME%" == "" goto gotHome
set CATALINA_HOME=.
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome

如果 catalina.bat 在其 bin 子目录下面没有找到,就无法调用 catalina.bat文件。然后批处理文件再猜一次,它查找 CATALINA_HOME 目录下面的 bin 子目录下面是否存在该文件:

set CATALINA_HOME=..
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome

如果猜测正确,它跳到 okHome。否则,打印出错误消息,告诉用户 CATALINA_HOME
设置错误并跳到 end,end 标签在该批处理文件末端:

echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end

如果 CATALINA_HOME 定义正确,且setenv.bat 文件存在,则批处理文件调用 stenv.bat 来设置需要的环境变量。如果不存在,并不会触发错误信息:

:okHome
rem Get standard environment variables
if exist "%CATALINA_HOME%\bin\setenv.bat" call
"%CATALINA_HOME%\bin\setenv.bat"

接下来,它检查 setclasspath.bat 文件是否存在,如果找不到该文件,则显示错误信息并跳到该批处理文件的 end 来退出批处理文件:

if exist "%CATALINA_HOME%\bin\setclasspath.bat" goto okSetclasspath
echo Cannot find %CATALINA_HOME%\bin\setclasspath.bat
echo This file is needed to run this program
goto end

如果找到 setclaspath.bat 文件,它设置 BASEDIR 变量的值为 CATALINA_HOME,然后调用调用 setclasspath.bat 文件来设置类路径:

:okSetclasspath
set BASEDIR=%CATALINA_HOME%
call "%CATALINA_HOME%\bin\setclasspath.bat"

setclasspath.bat 文件检查环境变量 JAVA_HOME 是否正确定义,然后使用catalina.bat 的其它部分继续设置接下来的变量:

set JAVA_ENDORSED_DIRS=%BASEDIR%\common\endorsed
set CLASSPATH=%JAVA_HOME%\lib\tools.jar
set _RUNJAVA="%JAVA_HOME%\bin\java"
set _RUNJAVAW="%JAVA_HOME%\bin\javaw"
set _RUNJDB="%JAVA_HOME%\bin\jdb"
set _RUNJAVAC="%JAVA_HOME%\bin\javac"

Catalina.bat 文件检测是否安装了 Java Secure Socket Extension 以及JSSE_HOME 的设置是否正确。如果找到了 JSSE_HOME 变量,将其添加到 CLASSPATH变量:

if "%JSSE_HOME%" == "" goto noJsse
set CLASSPATH=%CLASSPATH%;%JSSE_HOME%\lib\jcert.jar;%JSSE_HOME%\lib\jnet.
jar;%JSSE_HOME%\lib\jsse.jar

如果没找到 JSSE_HOME 变量,批处理文件则继续执行,它将 bin 目录下面的 bootstrap.jar 添加到 CLASSPATH 变量中:

:noJsse
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\bin\bootstrap.jar

接下来 catalina.bat 文件检查 CATALINA_BASE。如果 CATALINA_BASE 找不到,则创建它并值赋:

if not "%CATALINA_BASE%" == "" goto gotBase
set CATALINA_BASE=%CATALINA_HOME%
:gotBase

接下来,它检查 CATALINA_TMPDIR ,它表示 CATALINA_BASE 下面的 temporary目录:

if not "%CATALINA_TMPDIR%" == "" goto gotTmpdir
set CATALINA_TMPDIR=%CATALINA_BASE%\temp
:gotTmpdir

接下来,它显示几个变量的值:

echo Using CATALINA_BASE: %CATALINA_BASE%
echo Using CATALINA_HOME: %CATALINA_HOME%
echo Using CATALINA_TMPDIR: %CATALINA_TMPDIR%
echo Using JAVA_HOME: %JAVA_HOME%

然后它设置_EXECJAVA 的值为_RUNJAVA 变量的值。_RUNCJAVA 的值为%JAVA_HOME%\bin\java。换句话说,它指向 JAVA_HOME 目录下面 bin 子目录中的 java.exe:

set _EXECJAVA=%_RUNJAVA%

然后设置接下来的变量:

set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=

然后 catalina.bat 文件检查传递给它的第一个参数是否是 jpda,如果是,则将 JPDA变量的值设置为 jpda。然后检查 JPDA_TRANSPORT 和 JPDA_ADDRESS 变量,并移动参数:

if not ""%1"" == ""jpda"" goto noJpda
set JPDA=jpda
if not "%JPDA_TRANSPORT%" == "" goto gotJpdaTransport
set JPDA_TRANSPORT=dt_shmem
:gotJpdaTransport
if not "%JPDA_ADDRESS%" == "" goto gotJpdaAddress
set JPDA_ADDRESS=jdbconn
:gotJpdaAddress
shift

在大多数情况下并不会使用 JPDA,因此第一个参数必须下面之一: debug,embedded, run, start, 或 stop:

:noJpda
if ""%1"" == ""debug"" goto doDebug
if ""%1"" == ""embedded"" goto doEmbedded
if ""%1"" == ""run"" goto doRun
if ""%1"" == ""start"" goto doStart
if ""%1"" == ""stop"" goto doStop

如果第一个参数不正确或者没有参数,批处理文件显示使用说明并退出:

echo Usage: catalina ( commands ... )
echo commands:
echo debug Start Catalina in a debugger
echo debug -security Debug Catalina with a security manager
echo embedded Start Catalina in embedded mode
echo jpda start Start Catalina under JPDA debugger
echo run Start Catalina in the current window
echo run -security Start in the current window with security manager
echo start Start Catalina in a separate window
echo start -security Start in a separate window with security manager
echo stop Stop Catalina
goto end

如果第一个参数是 start,它转到 doStart 标签,如果是 stop,将转到doStop 标签。

在 doStart 标签之后,catalina.bat 文件调用 shift 命令检查下一个参数,如果有必须为-security。否则它被忽略。下一个参数是-security时,则再次调用 shift命令然后将 SECURITY_POLICY_FILE 变量值设置为%CATALINA_BASE%\conf\catalina.policy:

:doStart
shift
if not "%OS%" == "Windows_NT" goto noTitle
set _EXECJAVA=start "Tomcat" %_RUNJAVA%
goto gotTitle
:noTitle
set _EXECJAVA=start %_RUNJAVA%
:gotTitle
if not ""%1"" == ""-security"" goto execCmd
shift
echo Using Security Manager
set SECURITY_POLICY_FILE=%CATALINA_BASE%\conf\catalina.policy

在这一阶段,_EXECJAVA 的值是下面值之一:

start "Tomcat" "%JAVA_HOME%\bin\java"
start "%JAVA_HOME%\bin\java"

然后跳到 execCmd 标签中:

goto execCmd

在 execCmd 标签下面,获得未移动命令行参数并将其存储在 CMD_LINE_ARGS且跳到 doneSetArgs:

:execCmd
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs

下面是 doneSetArgs 标签下的命令:

:doneSetArgs
rem Execute Java with the applicable properties
if not "%JPDA%" == "" goto doJpda
if not "%SECURITY_POLICY_FILE%" == "" goto doSecurity
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -
Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -
Dcatalina.base="%CATALINA_BASE%" -Dcatalina.home="%CATALINA_HOME%" -
Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS%
%ACTION%

例如在我的电脑上,可以使用如下命令来调用 catalina start:

start "Tomcat" "C:\j2sdk1.4.2_02\bin\java"-Djava.endorsed.dirs="..\common\endorsed" -classpath
"C:\j2sdk1.4.2_02\lib\tools.jar;..\bin\bootstrap.jar"-Dcatalina.base=".."-Dcatalina,home=".."-Djava.io.tmpdir="..\temp" org.apache.catalina.startup.Bootstrap start

当通过传递不同的参数来调用catalina.bat文件时,应该弄清楚这个命令是什么。

17.3.3 Windows下启动Tomcat

如 Listing17.10 所示的 startup.bat 文件提供了简单方法来调用 catalina.bat文件,它传递参数 start 来调用 catalina.bat。

Listing 17.10: The startup.bat file

@echo off
if "%OS%" == "Windows_NT" setlocal
rem ----------------------------------------------------------------
rem Start script for the CATALINA Server
rem
rem $Id: startup.bat,v 1.4 2002/08/04 18:19:43 patrickl Exp $
rem ----------------------------------------------------------------
rem Guess CATALINA_HOME if not defined
if not "%CATALINA_HOME%" == "" goto gotHome
set CATALINA_HOME=.
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
set CATALINA_HOME=..
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
set EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat
rem Check that target executable exists
if exist "%EXECUTABLE%" goto okExec
echo Cannot find %EXECUTABLE%
echo This file is needed to run this program
goto end
:okExec
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
call "%EXECUTABLE%" start %CMD_LINE_ARGS%
:end
Stripping all rem and echo commands, you get the following:
if "%OS%" == "Windows_NT" setlocal
if not "%CATALINA_HOME%" == "" goto gotHome
set CATALINA_HOME=.
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
set CATALINA_HOME=..
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
goto end
:okHome
set EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat
if exist "%EXECUTABLE%" goto okExec
goto end
:okExec
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
call "%EXECUTABLE%" start %CMD_LINE_ARGS%
:end

17.3.4 Windows下停止Tomcat

如 Listing17.11 所示的shutdown.bat 文件提供了一种简单方式来运行 catalina.bat,传递一个参数stop 给它来停止Tomcat。

Listing 17.11: The shutdown.bat file

@echo off
if "%OS%" == "Windows_NT" setlocal
rem
---------------------------------------------------------------------------
rem Stop script for the CATALINA Server
rem
rem $Id: shutdown.bat,v 1.3 2002/08/04 18:19:43 patrickl Exp $
rem
---------------------------------------------------------------------------
rem Guess CATALINA_HOME if not defined
if not "%CATALINA_HOME%" == "" goto gotHome
set CATALINA_HOME=.
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
set CATALINA_HOME=..
:gotHome
if exist "%CATALINA_HOME%\bin\catalina.bat" goto okHome
echo The CATALINA_HOME environment variable is not defined correctly
echo This environment variable is needed to run this program
goto end
:okHome
set EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat
rem Check that target executable exists
if exist "%EXECUTABLE%" goto okExec
echo Cannot find %EXECUTABLE%
echo This file is needed to run this program
goto end
:okExec
rem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
call "%EXECUTABLE%" stop %CMD_LINE_ARGS%
:end

17.4 Linux平台运行Tomcat

在Unix/Linux下面,Tomcat 使用Shell 脚本来启动或者停止自己。这些脚本文件扩展名为.sh,并且位于%CATALINA_HOME%目录下子目录 bin下面。本节将会介绍 catalina.sh, startup.sh, shutdown.sh和setclasspath.sh 这四个脚本文件。

本节首先介绍 Shell 脚本,对于 Shell 脚本不熟悉的读者可以仔细阅读一下。然后涉及的内容是 catalina.sh、startip.sh 以及 shutdown.sh。setclasspath.sh会在catalina.sh中使用到,因此在介绍catalina.sh小节中会对其进行简单的介绍。

17.4.1 Shell脚本简介

本节介绍Shell 脚本的内容仅限于让大家能够读懂 Tomcat 的脚本,尤其是catalina.sh、startup.sh、shutdown.sh 以及 setclasspath.sh。并没完全的介绍 Shell脚本,需要的话请查阅其它资料。

本质上看,Shell 脚本是一个文本文件。可以使用 vi 或其它文本编辑器编辑它。可以使用如下语法来确保该文件被授权可执行:

$ chmod +x  scriptName
$ chmod 755  scriptName

这样将会给文件所有者设置读、写和执行权限,组及其它用户有该文件的读和执行权。接下来可使如下命令来执行脚本:

bash  scriptName
sh  scriptName
./ scriptName

脚本由解释器逐行执行。 您的shell脚本可以有任何扩展名或不扩展名。 然而,.sh扩展名是最常见的。

接下来是一些 Shell 脚本中常用命令,足够我们理解 Tomcat 中的 Shell 脚本。

comment:
使用#表示后面的文本被忽略不会被执行,#出现在一行的最前面的话那么这行都是注释。

# This is a comment

它也可以出现在语句的中间,这样#右边的字符都是注释:echo Hello # print Hello

clear:
使用 clear 命令来清除屏幕,例如下面的语句先清理屏幕,然后打印出一个字符串:

clear
echo Shell scripts are useful

exit:
使用 exit 命令可以退出 Shell 脚本。退出的情况有以下几种状态,0表示成功退出,非0值表示非正常退出。因此当你遇到一个问题退出,可以使用如下命令:exit 1

echo:
使用 echo 命令可以在屏幕上打印出一个字符串,例如下面的命令在控制台上打印出 ‘Hello World’:echo Hello World

调用函数:
可以使用句号(.)来调用一个函数或者调用其他 Shell 脚本。例如,下面命令调用同一个目录下面的 test.sh:. ./test.sh

系统&用户变量:
变量名必须是以数字字母或下划线开头。使用等号来给变量赋值,例如,如下命令设置变量 myVar 值为 Tooksie:myVar=Tootsie

注意在等号前后不能存在空白符,另外需要注意变量名是大小写敏感的。可以设置变量的值为空字符串或者直接将右边留空即将一个变量设置为 NULL:

myVar=
myVar=""

要访问一个变量的值,可以使用变量名前面加$来访问变量。例如,可以打印出变量 myVar 的值:

echo $myVar

Unix/Linux 系统提供了一些系统变量。例如 HOME 表示当前用户的 home 目录。PWD 表示用户当前目录,PATH 表示查找调用命令的路径,等等。

警告:在不明白更改系统变量值会带来什么后果之前应该不要改变其值。

expr:
使用 expr 表示一个表达式,一个表达式必须用引号(“)将其括起来。如下是用 Shell脚本来表示加法运算:

sum=`expr 100 + 200`
echo $sum

此处创建一个名为 sum 的变量并将其赋值为300。运行该段脚本可以在控制台上打印出 300。另一个例子:echoexpr 200 + 300 它将在屏幕上打印出:500。

特殊的uname表达式表示操作系统的名字。例如,如果你使用的是 Linux,下面的命令将会打印出 Linux 在控制台上:echo uname

特殊的dirname filePath返回文件目录,例如dirname/home/user1/test.sh 返回 /home/user1。

接收参数:
跟给函数传递参数一样可以传递参数给 Shell 脚本。可以使用 1访 2表示第二个参数,依次类推。$#命令获得参数个数,$@命令获得所有参数

shift:
shift命令将参数后移一位, 1 2 的值, 2 1 的值。

if … then … [else … ] fi:
If 语句块用于测试一个条件并执行适当的命令,它的语法如下:

if condition then
    list of commands
[else
    list of commands
]
fi

注意也可以使用 elif 代替 else if。

例如下面的例子在获得一个 start参数时打印出 Starting the application,收到 stop时打印出 Stopping the application。

if [ "$1" = "start" ]; then
    echo Starting the application
fi
if [ "$1" = "stop" ]; then
    echo Stopping the application
fi

注意在条件中,在[和]前后都必须有一个空格。 1 0表示用于执行脚本的命令`。例如,若执行命./test.sh,则$0就表示./test.sh。

下面的表示可选条件
•-f file , true is file exists
•-r file , true if you have read access to file
•-z string , true if string is empty
•-n string , true if string is not empty
•string1 = string2 , true if string1 equals string2
•string1 != string2 , true if string1 is not equal to string2

for Loop:
for循环的语法如下,

for {  var } in { list }
do
    list of commands
done

例如:

for i in 1 2 3
do
    echo iteration $i
done

则会打印出:

iteration 1
iteration 2
iteration 3

while Loop:
While 循环的语法如下

while [ condition ]
do
    list of commands
done

例如:

n=1
while [ $n -lt 3 ];
do
    echo iteration $n
    n=$((n + 1))
done

输出为:

iteration 1
iteration 2

[ $n -lt 3]中的-lt 表示 less than。所以它表示 n 的值小于 3。

case:
case 表示一个选择性执行的程序,语法如下:

case $variable-name in
pattern1)
    list of commands
    ;;
pattern2)
    list of commands
    ;;
*)
    list of commands
    ;;
esac

;;表示结束执行,*)表示没有其它模式匹配时执行。例如下面的脚本检查操作系统的名字。如果使用的不是 cygwin, OS400 或Linux,将打印出 Operating system not recogized:

case "`uname`" in
    CYGWIN*) echo cygwin;;
    OS400*) echo OS400;;
    Linux*) echo Linux;;
    *) echo Operating system not recognized
esac

输出重定向:
使用>将输出定位到文件中,例如。可以使用命令echo Hello > myFile.txt,则会创建一个名为 myFile.txt 的文件并将 Hello 写入到其中。屏幕上不会有显示。

注意: 1>&2 将 stdout 上的错误信息显示到 stderr 上,而 2>&1 将stderr的输出显示到 stdout 上。

条件执行:
可以写命令或条件的形式来决定执行哪个命令。这时候使用&&和||:

command1 && command2

如果 command1 返回一个0退出状态就执行 command2。Command1 也可以使用一个条件表达式来代替。如果条件为真,command2 将会执行,否则不执行 command2。

command1 || command2

如果 command1 的退出类型非 0,则执行 command2

command1 && command2 || command3

如果 command1 返回 0 退出状态,执行 command2,否则执行 command3。

17.4.2 catalina.sh脚本

Catalina.sh 用于在 Unix/Linux 下面启动或停止 Tomcat,启动时将 start传递给 catalina.sh,关闭时传递 stop 参数给它。下面是可用参数:
•debug. Start Catalina in a debugger (not available onOS400)
•debug -security. Debug Catalina with a security manager(not available on OS400)
•embedded. Start Catalina in embedded mode
•jpda start. Start Catalina under JPDA debugger
•run. Start Catalina in the current window
•run -security. Start in the current window with security manager
•start. Start Catalina in a separate window
•start -security. Start in a separate window with security manager
•stop. Stop Catalina
Catalina.sh 文件如 Listing17.12 所示:

Listing 17.12: The catalina.sh file

#!/bin/sh
#
-----------------------------------------------------------------------------
# Start/Stop Script for the CATALINA Server
#
# Environment Variable Prequisites
#
# CATALINA_HOME May point at your Catalina "build" directory.
#
# CATALINA_BASE (Optional) Base directory for resolving dynamic portions
# of a Catalina installation. If not present, resolves to
# the same directory that CATALINA_HOME points to.
#
# CATALINA_OPTS (Optional) Java runtime options used when the "start",
# "stop", or "run" command is executed.
#
# CATALINA_TMPDIR (Optional) Directory path location of temporary directory
# the JVM should use (java.io.tmpdir). Defaults to
# $CATALINA_BASE/temp.
#
# JAVA_HOME Must point at your Java Development Kit installation.
#
# JAVA_OPTS (Optional) Java runtime options used when the "start",
# "stop", or "run" command is executed.
#
# JPDA_TRANSPORT (Optional) JPDA transport used when the "jpda start"
# command is executed. The default is "dt_socket".
#
# JPDA_ADDRESS (Optional) Java runtime options used when the "jpda start"
# command is executed. The default is 8000.
#
# JSSE_HOME (Optional) May point at your Java Secure Sockets Extension
# (JSSE) installation, whose JAR files will be added to the
# system class path used to start Tomcat.
#
# CATALINA_PID (Optional) Path of the file which should contains the pid
# of catalina startup Java process, when start (fork) is used
#
# $Id: catalina.sh,v 1.8 2003/09/02 12:23:13 remm Exp $
#
-----------------------------------------------------------------------------
# OS specific support. $var _must_ be set to either true or false.
cygwin=false
os400=false
case "`uname`" in
CYGWIN*) cygwin=true;;
OS400*) os400=true;;
esac
# resolve links - $0 may be a softlink
PRG="$0"
while [ -h "$PRG" ]; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '.*/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`/"$link"
fi
done
# Get standard environment variables
PRGDIR=`dirname "$PRG"`
CATALINA_HOME=`cd "$PRGDIR/.." ; pwd`
if [ -r "$CATALINA_HOME"/bin/setenv.sh ]; then
. "$CATALINA_HOME"/bin/setenv.sh
fi
# For Cygwin, ensure paths are in UNIX format before anything is
touched
if $cygwin; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CATALINA_HOME" ] && CATALINA_HOME=`cygpath --unix
"$CATALINA_HOME"`
[ -n "$CATALINA_BASE" ] && CATALINA_BASE=`cygpath --unix
"$CATALINA_BASE"`
[ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
[ -n "$JSSE_HOME" ]  && JSSE_HOME=`cygpath --path --unix "$JSSE_HOME"`
fi
# For OS400
if $os400; then
# Set job priority to standard for interactive (interactive - 6) by
using
# the interactive priority - 6, the helper threads that respond to
requests
# will be running at the same priority as interactive jobs.
COMMAND='chgjob job('$JOBNAME') runpty(6)'
system $COMMAND
# Enable multi threading
export QIBM_MULTI_THREADED=Y
fi
# Get standard Java environment variables
if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then
BASEDIR="$CATALINA_HOME"
. "$CATALINA_HOME"/bin/setclasspath.sh
else
echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh"
echo "This file is needed to run this program"
exit 1
fi
# Add on extra jar files to CLASSPATH
if [ -n "$JSSE_HOME" ]; then
CLASSPATH="$CLASSPATH":"$JSSE_HOME"/lib/jcert.jar:"$JSSE_HOME"/lib/jn
et
.jar:"$JSSE_HOME"/lib/jsse.jar
fi
CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar
if [ -z "$CATALINA_BASE" ] ; then
CATALINA_BASE="$CATALINA_HOME"
fi
if [ -z "$CATALINA_TMPDIR" ] ; then
# Define the java.io.tmpdir to use for Catalina
CATALINA_TMPDIR="$CATALINA_BASE"/temp
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
CATALINA_HOME=`cygpath --path --windows "$CATALINA_HOME"`
CATALINA_BASE=`cygpath --path --windows "$CATALINA_BASE"`
CATALINA_TMPDIR=`cygpath --path --windows "$CATALINA_TMPDIR"`
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
JSSE_HOME=`cygpath --path --windows "$JSSE_HOME"`
fi
# ----- Execute The Requested Command -----------------------------------------
echo "Using CATALINA_BASE: $CATALINA_BASE"
echo "Using CATALINA_HOME: $CATALINA_HOME"
echo "Using CATALINA_TMPDIR: $CATALINA_TMPDIR"
echo "Using JAVA_HOME: $JAVA_HOME"
if [ "$1" = "jpda" ] ; then
if [ -z "$JPDA_TRANSPORT" ]; then
JPDA_TRANSPORT="dt_socket"
fi
if [ -z "$JPDA_ADDRESS" ]; then
JPDA_ADDRESS="8000"
fi
if [ -z "$JPDA_OPTS" ]; then
JPDA_OPTS="-Xdebug -
Xrunjdwp:transport=$JPDA_TRANSPORT,address=$JPDA_ADDRESS,server=y,sus
pe
nd=n"
fi
CATALINA_OPTS="$CATALINA_OPTS $JPDA_OPTS"
shift
fi
if [ "$1" = "debug" ] ; then
if $os400; then
echo "Debug command not available on OS400"
exit 1
else
shift
if [ "$1" = "-security" ] ; then
echo "Using Security Manager"
shift
exec "$_RUNJDB" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath"$CLASSPATH" \
-sourcepath "$CATALINA_HOME"/../../jakarta-tomcat-4.0/catalina/src/share \
-Djava.security.manager \
-Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy\
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start
else
exec "$_RUNJDB" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH" \
-sourcepath "$CATALINA_HOME"/../../jakarta-tomcat-4.0/catalina/src/share \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start
fi
fi
elif [ "$1" = "embedded" ] ; then
shift
echo "Embedded Classpath: $CLASSPATH"
exec "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath "$CLASSPATH"\
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Embedded "$@"
elif [ "$1" = "run" ]; then
shift
if [ "$1" = "-security" ] ; then
echo "Using Security Manager"
shift
exec "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath"$CLASSPATH" \
-Djava.security.manager \
-Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start
else
exec "$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath"$CLASSPATH" \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start
fi
elif [ "$1" = "start" ] ; then
shift
touch "$CATALINA_BASE"/logs/catalina.out
if [ "$1" = "-security" ] ; then
echo "Using Security Manager"
shift
"$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath"$CLASSPATH" \
-Djava.security.manager \
-Djava.security.policy=="$CATALINA_BASE"/conf/catalina.policy \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start \
>> "$CATALINA_BASE"/logs/catalina.out 2>&1 &
if [ ! -z "$CATALINA_PID" ]; then
echo $! > $CATALINA_PID
fi
else
"$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -classpath"$CLASSPATH" \
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" start \
>> "$CATALINA_BASE"/logs/catalina.out 2>&1 &
if [ ! -z "$CATALINA_PID" ]; then
echo $! > $CATALINA_PID
fi
fi
elif [ "$1" = "stop" ] ; then
shift
"$_RUNJAVA" $JAVA_OPTS $CATALINA_OPTS \
-Djava.endorsed.dirs="$JAVA_ENDORSED_DIRS" -clasapath "$CLASSPATH"\
-Dcatalina.base="$CATALINA_BASE" \
-Dcatalina.home="$CATALINA_HOME" \
-Djava.io.tmpdir="$CATALINA_TMPDIR" \
org.apache.catalina.startup.Bootstrap "$@" stop
if [ "$1" = "-force" ] ; then
shift
if [ ! -z "$CATALINA_PID" ]; then
echo "Killing: `cat $CATALINA_PID`"
kill -9 `cat $CATALINA_PID`
fi
fi
else
echo "Usage: catalina.sh ( commands ... )"
echo "commands:"
if $os400; then
echo " debug Start Catalina in a debugger (notavailable on OS400)"
echo " debug -security Debug Catalina with a security manager(not available on OS400)"
else
echo " debug Start Catalina in a debugger"
echo " debug -security Debug Catalina with a security manager"
fi
echo " embedded Start Catalina in embedded mode"
echo " jpda start Start Catalina under JPDA debugger"
echo " run Start Catalina in the current window"
echo " run -security Start in the current window with security manager"
echo " start Start Catalina in a separate window"
echo " start -security Start in a separate window with security manager"
echo " stop Stop Catalina"
exit 1
fi

17.4.3 Linux下启动Tomcat

简单起见,可以使用 startup.sh 来启动 Tomcat,startup.sh 设置了正确的环境变量通过传递参数start调用 catalina.sh。startup.sh 如 Listing17.13 所示:

Listing 17.13: The startup.sh file

#!/bin/sh
#
------------------------------------------------------------------------------
# Start Script for the CATALINA Server
#
# $Id: startup.sh,v 1.3 2002/08/04 18:19:43 patrickl Exp $
#
-----------------------------------------------------------------------------
# resolve links - $0 may be a softlink
PRG="$0"

while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '.*/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`/"$link"
    fi
done

PRGDIR=`dirname "$PRG"`
EXECUTABLE=catalina.sh

# Check that target executable exists
if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
    echo "Cannot find $PRGDIR/$EXECUTABLE"
    echo "This file is needed to run this program"
    exit 1
fi

exec "$PRGDIR"/"$EXECUTABLE" start "$@"

17.4.4 Linux下停止Tomcat

可以使用 shutdown.sh 脚本来简单地关闭 Tomcat,该脚本传递 stop 作为参数给catalina.sh。如Listing 17.14所示:

Listing 17.14: The shutdown.sh File

#!/bin/sh
#
---------------------------------------------------------------------
# Stop script for the CATALINA Server
#
# $Id: shutdown.sh,v 1.3 2002/08/04 18:19:43 patrickl Exp $
#
---------------------------------------------------------------------
# resolve links - $0 may be a softlink
PRG="$0"

while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '.*/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`/"$link"
    fi
done

PRGDIR=`dirname "$PRG"`
EXECUTABLE=catalina.sh

# Check that target executable exists
if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
    echo "Cannot find $PRGDIR/$EXECUTABLE"
    echo "This file is needed to run this program"
    exit 1
fi

exec "$PRGDIR"/"$EXECUTABLE" stop "S@"

17.5 小结

本章介绍了用于启动应用程序的两个类:Catalina和Bootstrap,它们都是org.apache.catalina.startup包下面的成员。另外我们还学习了Bat和Shell 脚本,简便地来启动和停止Tomcat。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值