1. 程式人生 > >How Tomcat works 16-17: ShutdownHook 和Tomcat啟動

How Tomcat works 16-17: ShutdownHook 和Tomcat啟動

Shutdown Hook

一、概述     1. JVM會響應關閉自己的兩種Event     (1)應用程式呼叫System.exit方法或最後一個非守護程序non-daemon退出     (2)使用者在關java程式之前,突然強制關機,比如CTRL+C或者登出系統     2. JVM為shuttingdown提供了兩段式處理流程     (1)JVM會和所有註冊過的shutdown hooks一起啟動。這些註冊的shutdown hooks會在執行時作為執行緒執行。所有shutdown hooks都會並行執行結束     (2)適當情況下,JVM會呼叫所有未呼叫的finalizers     3. Shutdown hook建立步驟:     (1)寫Thread類的子類     (2)提供run()方法的實現程式碼,用於當突然或正常關機時執行     (3)例項化這個shutdownhook類     (4)呼叫當前runtime的addShutdownHook()方法註冊shutdownhook     4. 例項 

 public class ShutdownHookDemo {
        
            public  static void main(String[] args) {
                System.out.println("start demo...");
                ShutdownHookDemo demo = new ShutdownHookDemo();
                demo.start();
                
                // 讀取console輸入後,正常退出程式,會呼叫hook.run()
                try {
                    System.in.read();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            private void start() {
                ShutdownHook shutdownHook = new ShutdownHook();
                Runtime.getRuntime().addShutdownHook(shutdownHook);
            }
            
            class ShutdownHook extends Thread{
                public void run() {
                    System.out.println("Running ShutdownHook");
                }
            }
        }

    5. Tomcat的CatalinaShutdowHook程式碼       

  public class CatalinaShutdownHook extends Thread{
            public void run() {
                if(server != null) {
                    ((Lifecycle)server).stop();
                }
            }
        }

Tomcat啟動    

 1. 概述     (1)啟動類:     Catalina: 用來啟動和停止Server物件,同時解析Tomcat的配置檔案server.xml     Bootstrap:建立Catalina例項和呼叫其process方法的接入點。針對不同場景會有多個Bootstrap實現,如Bootstrap類用來啟動單機版,BootstrapService用來啟動WindowsNT service的tomcat。Tomcat提供了batch/shell指令碼檔案來啟動,無需使用者關注使用哪個啟動類的細節     2. Catalina類     (1)process()方法         

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

    (2)arguments(args)方法         

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

    (3)execute方法         

             /**
             * Execute the processing that has been configured from the command line.
             */
            protected void execute() throws Exception {
        
                if (starting)
                    start();
                else if (stopping)
                    stop();
            }

    (4)start方法:           程式碼:         

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

    (5)Digester createStartDigester()和Digester createStopDigester(),新增各種xml解析規則          3. Bootstrap類          程式碼:         

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