Catalina.class在tomcat中是一个与服务器直接相关的很重要的类。相于一个中间层,也可认为一个控制服务器的工具类。从BootStrap.class里对Catalina.class的按顺序运用,有下面这些。1.在BootStrap.class的init()方法里通反射机制创建一个Catalina.class的一个实例。代码如下: Class startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance();再去调用Catalina.class的setParentClassLoader(ClassLoader classLoader)方法,代码如下: 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.class的setParentClassLoader(ClassLoader classLoader)方法是把sharedLoader这个加载器 传递给Catalina.class同作为它的加载器。 同里也这个Catalina.class实例的引用保存在BootStrap.class中,代码:catalinaDaemon = startupInstance; 2.有上面所得到Catalina.class的实例对象引用去调用load()/load(String args[])方法。在我们启动的时候是调用load(String args[])方法,这里的参数是"start".这个方法其就是根据参数去设定一些变量的初始值,参数是“start”的实例就把启动(starting)设为true,把停止(stopping)设为false.再来去调用没有参数的load()方法,这个方法调用了其它一些方法:首先是调用initDirs()方法,initDirs()方法是从父类Embedded.class继承下来,作用就是看相应的目录属性是否已经初始化了(catalina.home,catalina.base)。如果已经初始化了就什么也不做,没有就进行相应的初始。有的人可能会觉得很奇怪,前面在BootStrap.class中不是已经初始化了吗,为什么这里还要多些一举呢?其Catalina.class是可以不需要BootStrap.class直接启动的,也就是没有BootStrap.class一样可以运行tomcat.BootStap.class只是提供了一个预处理的过理。其次是调用initNaming()方法,这个方法是初始化一些系统参数的值包括:("catalina.useNaming",true),(javax.naming.Context.URL_PKG_PREFIXES,"org.apache.naming"),(javax.naming.Context.INITIAL_CONTEXT_FACTORY,"org.apache.naming.java.javaURLContextFactory")对这几个属性做什么用的可参见JDK API javax.naming.Context.class类的说明。再次是通过createStartDigester()方法创建 Digester.class类的实例对象,这个createStartDigester()就是调用Disgester.class的一些方法实现服务器Server.class相关资源的初始化。然后加载配置文件server.xml,对通过Digester.class的实例对server.xml进行解释和处理。Digester.class是怎么实现的需要后面对其代码进行分析。最后就是最重的东西, 那就是Server.class,调用Server.class的initialize()方法。初始化服务器。 下一片:Digester.class 附源码:Catalina.class-------------------------------------------------------------------------------------------------------/* * Copyright 1999,2004 The Apache Software Foundation. * * Licensed 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.io.FileInputStream;import java.io.InputStream;import java.io.IOException;import java.io.OutputStream;import java.net.Socket;import org.apache.catalina.Container;import org.apache.catalina.Lifecycle;import org.apache.catalina.LifecycleException;import org.apache.catalina.Server;import org.apache.catalina.core.StandardServer;import org.apache.tomcat.util.digester.Digester;import org.apache.tomcat.util.digester.Rule;import org.xml.sax.Attributes;import org.xml.sax.InputSource;/** * Startup/Shutdown shell program for Catalina. The following command line * options are recognized: *
* - -config {pathname} - Set the pathname of the configuration file * to be processed. If a relative path is specified, it will be * interpreted as relative to the directory pathname specified by the * "catalina.base" system property. [conf/server.xml] *
- -help - Display usage information. *
- -stop - Stop the currently running instance of Catalina. * * * Should do the same thing as Embedded, but using a server.xml file. * * @author Craig R. McClanahan * @author Remy Maucherat * @version $Revision: 380229 $ $Date: 2006-02-23 22:28:29 +0100 (jeu., 23 f茅vr. 2006) $ */public class Catalina extends Embedded { // ----------------------------------------------------- Instance Variables /** * Pathname to the server configuration file. */ protected String configFile = "conf/server.xml"; // XXX Should be moved to embedded /** * The shared extensions class loader for this server. */ protected ClassLoader parentClassLoader = Catalina.class.getClassLoader(); /** * The server component we are starting or stopping */ protected Server server = null; /** * Are we starting a new server? */ protected boolean starting = false; /** * Are we stopping an existing server? */ protected boolean stopping = false; /** * Use shutdown hook flag. */ protected boolean useShutdownHook = true; /** * Shutdown hook. */ protected Thread shutdownHook = null; // ------------------------------------------------------------- Properties public void setConfig(String file) { System.out.println("Catalina.class setConfig(String file) method"); configFile = file; } public void setConfigFile(String file) { System.out.println("Catalina.class setConfigFile(String file) method"); configFile = file; } public String getConfigFile() { System.out.println("Catalina.class getConfigFile() method"); return configFile; } public void setUseShutdownHook(boolean useShutdownHook) { System.out.println("Catalina.class setUseShutdownHook(boolean useShutdownHook) method"); this.useShutdownHook = useShutdownHook; } public boolean getUseShutdownHook() { System.out.println("Catalina.class getUseShutdownHook() method"); return useShutdownHook; } /** * Set the shared extensions class loader. * * @param parentClassLoader The shared extensions class loader. */ public void setParentClassLoader(ClassLoader parentClassLoader) { System.out.println("Catalina.class setParentClassLoader(ClassLoader parentClassLoader) method"); this.parentClassLoader = parentClassLoader; } /** * Set the server instance we are configuring. * * @param server The new server */ public void setServer(Server server) { System.out.println("Catalina.class setServer(Server server) method"); this.server = server; } // ----------------------------------------------------------- Main Program /** * The application main program. * * @param args Command line arguments */ public static void main(String args[]) { System.out.println("Catalina.class main(String args[]) method"); (new Catalina()).process(args); } /** * The instance main program. * * @param args Command line arguments */ public void process(String args[]) { System.out.println("Catalina.class process(String args[]) method"); setAwait(true); setCatalinaHome(); setCatalinaBase(); try { if (arguments(args)) { if (starting) { load(args); start(); } else if (stopping) { stopServer(); } } } catch (Exception e) { e.printStackTrace(System.out); } } // ------------------------------------------------------ Protected Methods /** * Process the specified command line arguments, and return *
true
if we should continue processing; otherwise * return false
. * * @param args Command line arguments to process */ protected boolean arguments(String args[]) { System.out.println("Catalina.class arguments(String args[]) method"); 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("-nonaming")) { setUseNaming( false ); } else if (args[i].equals("-help")) { usage(); return (false); } else if (args[i].equals("start")) { starting = true; stopping = false; } else if (args[i].equals("stop")) { starting = false; stopping = true; } else { usage(); return (false); } } return (true); } /** * Return a File object representing our configuration file. */ protected File configFile() { System.out.println("Catalina.class configFile() method"); File file = new File(configFile); if (!file.isAbsolute()) file = new File(System.getProperty("catalina.base"), configFile); return (file); } /** * Create and configure the Digester we will be using for startup. */ protected Digester createStartDigester() { long t1=System.currentTimeMillis(); // Initialize the digester Digester digester = new Digester(); digester.setValidating(false); digester.setClassLoader(StandardServer.class.getClassLoader()); // 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.addRule("Server/Service/Connector", new ConnectorCreateRule()); digester.addRule("Server/Service/Connector", new SetAllPropertiesRule()); digester.addSetNext("Server/Service/Connector","addConnector", "org.apache.catalina.connector.Connector"); digester.addObjectCreate("Server/Service/Connector/Listener",null, "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/Host/")); digester.addRuleSet (ClusterRuleSetFactory.getClusterRuleSet"Server/Service/Engine/Host/Cluster/")); digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/")); // When the 'engine' is found, set the parentClassLoader. digester.addRule("Server/Service/Engine",new SetParentClassLoaderRule(parentClassLoader)); digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/")); long t2=System.currentTimeMillis(); if (log.isDebugEnabled()) log.debug("Digester for server.xml created " + ( t2-t1 )); return (digester); } /** * Create and configure the Digester we will be using for shutdown. */ protected Digester createStopDigester() { // Initialize the digester Digester digester = new Digester(); // 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); } public void stopServer() { stopServer(null); } public void stopServer(String[] arguments) { if (arguments != null) { arguments(arguments); } if( server == null ) { // Create and execute our Digester Digester digester = createStopDigester(); digester.setClassLoader(Thread.currentThread().getContextClassLoader()); 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) { log.error("Catalina.stop: ", e); 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) { log.error("Catalina.stop: ", e); System.exit(1); } } /** * Set the catalina.base
System property to the current * working directory if it has not been set. * @deprecated Use initDirs() */ public void setCatalinaBase() { System.out.println("Catalina.class setCatalinaBase() method"); initDirs(); } /** * Set the catalina.home
System property to the current * working directory if it has not been set. * @deprecated Use initDirs() */ public void setCatalinaHome() { System.out.println("Catalina.class setCatalinaHome() method"); initDirs(); } /** * Start a new server instance. */ public void load() { System.out.println("Catalina.class load() method"); initDirs(); // Before digester - it may be needed initNaming(); // Create and execute our Digester Digester digester = createStartDigester(); long t1 = System.currentTimeMillis(); Exception ex = null; InputSource inputSource = null; InputStream inputStream = null; File file = null; try { file = configFile(); inputStream = new FileInputStream(file); inputSource = new InputSource("file://" + file.getAbsolutePath()); } catch (Exception e) { ; } if (inputStream == null) { try { inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile()); inputSource = new InputSource (getClass().getClassLoader().getResource(getConfigFile()).toString()); } catch (Exception e) { ; } } // This should be included in catalina.jar // Alternative: don't bother with xml, just create it manually. if( inputStream==null ) { try { inputStream = getClass().getClassLoader() .getResourceAsStream("server-embed.xml"); inputSource = new InputSource (getClass().getClassLoader() .getResource("server-embed.xml").toString()); } catch (Exception e) { ; } } if ((inputStream == null) && (file != null)) { log.warn("Can't load server.xml from " + file.getAbsolutePath()); return; } try { inputSource.setByteStream(inputStream); digester.push(this); digester.parse(inputSource); inputStream.close(); } catch (Exception e) { log.warn("Catalina.start using " + getConfigFile() + ": " , e); return; } // Stream redirection initStreams(); // Start the new server if (server instanceof Lifecycle) { try { server.initialize(); } catch (LifecycleException e) { log.error("Catalina.start", e); } } long t2 = System.currentTimeMillis(); if(log.isInfoEnabled()) log.info("Initialization processed in " + (t2 - t1) + " ms"); } /* * Load using arguments */ public void load(String args[]) { System.out.println("Catalina.class load(String args[]) method"); try { if (arguments(args)) load(); } catch (Exception e) { e.printStackTrace(System.out); } } public void create() { System.out.println("Catalina.class create() method"); } public void destroy() { System.out.println("Catalina.class destroy() method"); } /** * Start a new server instance. */ public void start() { if (server == null) { load(); } long t1 = System.currentTimeMillis(); // Start the new server if (server instanceof Lifecycle) { try { ((Lifecycle) server).start(); } catch (LifecycleException e) { log.error("Catalina.start: ", e); } } long t2 = System.currentTimeMillis(); if(log.isInfoEnabled()) log.info("Server startup in " + (t2 - t1) + " ms"); try { // Register shutdown hook if (useShutdownHook) { if (shutdownHook == null) { shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook); } } catch (Throwable t) { // This will fail on JDK 1.2. Ignoring, as Tomcat can run // fine without the shutdown hook. } if (await) { await(); stop(); } } /** * Stop an existing server instance. */ public void stop() { try { // Remove the ShutdownHook first so that server.stop() // doesn't get invoked twice if (useShutdownHook) { Runtime.getRuntime().removeShutdownHook(shutdownHook); } } catch (Throwable t) { // This will fail on JDK 1.2. Ignoring, as Tomcat can run // fine without the shutdown hook. } // Shut down the server if (server instanceof Lifecycle) { try { ((Lifecycle) server).stop(); } catch (LifecycleException e) { log.error("Catalina.stop", e); } } } /** * Await and shutdown. */ public void await() { System.out.println("Catalina.class await() method"); server.await(); } /** * Print usage information for this application. */ protected void usage() { System.out.println("Catalina.class usage() method"); System.out.println ("usage: java org.apache.catalina.startup.Catalina" + " [ -config {pathname} ]" + " [ -nonaming ] { start | stop }"); } // --------------------------------------- CatalinaShutdownHook Inner Class // XXX Should be moved to embedded ! /** * Shutdown hook which will perform a clean shutdown of Catalina if needed. */ protected class CatalinaShutdownHook extends Thread { public CatalinaShutdownHook(){ System.out.println("Catalina.CatalinaShutdownHook.class CatalinaShutdownHook() constructor method"); } public void run() { System.out.println("Catalina.CatalinaShutdownHook.class run() method"); if (server != null) { Catalina.this.stop(); } } } private static org.apache.juli.logging.Log log= org.apache.juli.logging.LogFactory.getLog( Catalina.class );}// ------------------------------------------------------------ Private Classes/** * Rule that sets the parent class loader for the top object on the stack, * which must be a Container
. */final class SetParentClassLoaderRule extends Rule { public SetParentClassLoaderRule(ClassLoader parentClassLoader) { System.out.println("Catalina.SetParentClassLoaderRule.class SetParentClassLoaderRule(ClassLoader parentClassLoader) constructor method"); this.parentClassLoader = parentClassLoader; } ClassLoader parentClassLoader = null; public void begin(String namespace, String name, Attributes attributes) throws Exception { System.out.println("Catalina.SetParentClassLoaderRule.class begin(String namespace, String name, Attributes attributes) method"); if (digester.getLogger().isDebugEnabled()) digester.getLogger().debug("Setting parent class loader"); Container top = (Container) digester.peek(); top.setParentClassLoader(parentClassLoader); }}