Tomcat Source Analysis Three: Tomcat start and stop

Source: Internet
Author: User
Tags reflection sleep socket throwable port number server port tomcat
General overview

The Tomcat class has three modes of operation, and when Tomcat is used as a "standalone servlet container", Tomcat starts and stops by executing a script in the bin directory. The entry method of the script is the main method of Bootstrap. The specific start-up and stop are implemented by bootstrap reflection calls to the Catalina instance. Catalina is a starting class for the Tomcat life, Bootstrap is encapsulated in the Catalina class and provides the main () method for easy invocation. Let's look at the start and stop process of Tomcat.

Tomcat runs can be divided into the following three stages
1. Start the process: start the corresponding server,service,connector and other components
2. Response process: The main thread waits to receive a stop Tomcat signal, and other threads receive and request processing.
3. End process: After receiving the stop signal, close Tomcat general analysis

First look at the definition of entrance class bootstrap

Several important properties private static Bootstrap daemon = null;
Instance of the Catalina class private Object Catalinadaemon = null;
Three important ClassLoader ClassLoader commonloader = null;
ClassLoader catalinaloader = null;


ClassLoader sharedloader = null; public static void Main (String args[]) {if (daemon = = null) {//Don ' t set daemon until init () has C
            ompleted Bootstrap Bootstrap = new Bootstrap ();
            try {bootstrap.init ();
                } catch (Throwable t) {handlethrowable (t);
                T.printstacktrace ();
            Return
        } daemon = bootstrap;  } else {//when running as a service the ' call ' to stop would be ' on a new//thread so make sure the correct
        Class loader is used to prevent//a range of class not found exceptions. Thread. CurrentThread (). Setcontextclassloader (daemon.
    Catalinaloader);
            } try {String command = "Start"; IF (Args.length > 0) {command = args[args.length-1];
                } if (Command.equals ("STARTD")) {args[args.length-1] = "Start";
                Daemon.load (args);
            Daemon.start ();
                } else if (Command.equals ("STOPD")) {args[args.length-1] = "Stop";
            Daemon: Stop ();
                } else if (Command.equals ("start")) {daemon.setawait (true);
                Daemon.load (args);
            Daemon.start ();
            } else if (Command.equals ("Stop")) {daemon.stopserver (args);
                } else if (Command.equals ("Configtest")) {daemon.load (args); if (Null==daemon.
                Getserver ()) {system.exit (1);
            } system.exit (0); } else {log.warn ("Bootstrap:command \" "+ Command +" \ "does not exist.
            ");
}} catch (Throwable t) {            Unwrap the Exception for clearer error reporting if (t instanceof invocationtargetexception &am
            p;& t.getcause ()! = null) {T = T.getcause ();
            } handlethrowable (t);
            T.printstacktrace ();
        System.exit (1); }

    }

The main () method first determines whether daemon is null, and each time a script executes the main () function, it must be a new thread, so the deamon here must be empty, and when daemon is empty, the init () method is called, The main function of the method is to initialize the related ClassLoader, create the Catalinadaemon, that is, the Catalina instance, and set the corresponding parentclassloader to the Catalinadaemon, Finally, the newly created bootstrap is set to Deamon.
And then processing the specific commands and parameters, see the main number of calls to the method is

Daemon.setawait (true);  Set up await
daemon.load (args);      Load config
daemon.start ();         Start Service
daemon.stop ();          Stop service
daemon.stopserver (args);   Stop server

The implementation of the above five functions, respectively, is to invoke the Setawait,load,start,stop,stopserver method of Catalinadaemon by reflection. These five methods are the core approach to Tomcat start and stop. These five methods complete tomcat boot, main thread wait, Tomcat stop function, stop function is stop service, and Stopserver function is to send Stop command.

Let's start with the definition of the properties of the Catalina class

Protected Boolean await = false;
 protected server server = NULL;  There is one property in Catalina for server, and all operations on the server are for this, and the server is obtained by parsing the XML file.
setting up await

There are two methods associated with an await. An await is a simple variable that the main thread determines whether to wait based on that variable. It will be mentioned again below.

    public void Setawait (Boolean b) {
        await = B;
    }

    public Boolean isawait () {
        return await;
    }
Load Configuration
public void Load () {initdirs ();

        Create and execute our digester digester digester = Createstartdigester ();
        InputSource inputsource = null;
        InputStream inputstream = null;
        File file = null; try {//below omit the detailed code to find the configuration file, you can download the specific source view. Main process Find "conf/server.xml" if not found, look for "server-embed.
            XML "file if (InputStream = = NULL | | inputsource = = NULL) {return;
                } try {Inputsource.setbytestream (InputStream);
                Digester.push (this);
            Digester.parse (InputSource);
            } catch (Exception e) {return; }} finally {if (InputStream! = null) {try {inputstream.close ()
                ; } catch (IOException e) {//Ignore}}} getserver (). Set
        Catalina (this); Getserver (). SetcatalinAhome (Bootstrap.
        Getcatalinahomefile ()); Getserver (). Setcatalinabase (Bootstrap.

        Getcatalinabasefile ());

        Stream redirection initstreams ();
        Start the new server try {getserver (). Init (); } catch (Lifecycleexception e) {}}

The main function above is to load tomcat according to the configuration file such as/conf/server.xml, which can be divided into several steps to initialize the Digester: Configure a parser to parse/conf/server.xml to find the configuration file (/conf/server.xml or Server-embed.xml) parse the configuration file to initialize the server (the properties that are equivalent to server settings are described in detail below)

Calling the server's init () method: Modifying the lifecycle State, invoking the service's init () method

The 1th step is to build a parser to parse the configuration file (corresponding to the configuration file), the 2nd step is omitted in the code, and the 3rd step is to parse the corresponding configuration file using the parser. Let's see how the file is parsed. parsing Files

Parsing the file is done through Digester. The following is a brief introduction to Digester, from the Baidu Encyclopedia, and made a certain change

Digester was originally a tool in Jakarta struts to handle struts-config. XML configuration file. Now digester with the development of struts and its utility is mentioned in Commons, a component of Apache Apache Commons-digester.jar, which makes it easy to generate Java objects from XML files. You don't have to read a Document object again like you used to Jdom or xerces. Digester is driven by an "event", which converts an XML file into a Java object by invoking a predefined rule action object stack.

Attach a default/conf/server.xml configuration, remove the comment

<?xml version= "1.0" encoding= "UTF-8"?> <server port= "8005" shutdown= "shutdown" > <listener classname= " Org.apache.catalina.startup.VersionLoggerListener "/> <listener classname=" Org.apache.catalina.core.AprLifecycleListener "sslengine=" on "/> <listener classname=" Org.apache. Catalina.core.JreMemoryLeakPreventionListener "/> <listener classname=" Org.apache.catalina.mbeans.GlobalResourcesLifecycleListener "/> <listener classname=" Org.apache.catalina.core.ThreadLocalLeakPreventionListener "/> <GlobalNamingResources> <resource name= "Userdatabase" auth= "Container" type= "Org.apache.catalina.UserDatabase" description= "User database tha T can be updated and saved "factory=" Org.apache.catalina.users.MemoryUserDatabaseFactory "Pathname=" Co Nf/tomcat-users.xml "/> </GlobalNamingResources> <service name=" Catalina "> <connector port=" 8080 " Protocol= "http/1.1" connectiontimeout= "20000"
           redirectport= "8443"/> <connector port= "8009" protocol= "ajp/1.3" redirectport= "8443"/> <Engine na Me= "Catalina" defaulthost= "localhost" > <realm classname= "Org.apache.catalina.realm.LockOutRealm" > < 

  Realm classname= "Org.apache.catalina.realm.UserDatabaseRealm" resourcename= "Userdatabase"/> </Realm>  

The above configuration is the default/conf/server.xml configuration, and Digester initializes the server with this configuration. As you can see from this configuration, a string with a port number of 8005, ' shutdown ' as ' shutdown ' is defined, and the two are for stopping the Tomcat service. The outermost element is server, and the server has a service,service with two connector and one is HTTP/1. 1, the other one is AJP/1. 3, the engine associated with the connector name is Catalina, and its default host is Defaulthost. And a default host is defined. Inside this, there is no definition of context and wrapper.
The role of digester is to translate this file into the definition of the corresponding class. Therefore, in the actual Tomcat component, the server has only one service, the service has two connector and one engine. Specific can refer to Tomcat source Analysis one: General introduction (Other same configuration file, not detailed expansion) start the service

Look at the code first

public void Start () {if (getserver () = = null) {load (); } if (getserver () = = null) {log. Fatal ("Cannot start server. Server instance is not configured.
            ");
        Return
        }//Start the new server try {getserver (). Start ();
        } catch (Lifecycleexception e) {return;
                }//Register shutdown hook if (useshutdownhook) {if (Shutdownhook = = null) {
            Shutdownhook = new Catalinashutdownhook ();

            } runtime.getruntime (). Addshutdownhook (Shutdownhook); If Juli is being used, disable Juli ' s shutdown hooks since//shutdown hooks run in parallel and log message s may lost//if Juli ' s hook completes before the Catalinashutdownhook () Logmanager Logmanager
            = Logmanager.getlogmanager (); if (Logmanager instanceof Classloaderlogmanager) {(ClaSsloaderlogmanager) Logmanager).
            Setuseshutdownhook (FALSE);
            }} if (await) {await ();
        Stop (); }
    }

Start () mainly completes the following function call Server.start (): Change the current life cycle state, and by calling Service.start () to start the corresponding Engine,host,connector, etc., you can start to receive and processing requests. The later time will be expanded in detail. If Useshutdownhook is true, configure the service to stop when the hook, this is mainly concerned about the abnormal shutdown when Tomcat, the related services can be closed gracefully.

If await is true, call await (), after the await () is complete, call the Stop () method when Tomcat is used as a standalone servlet container, because the setawait () setting that is described above is invoked to set the await variable to true. The main function of await () is to implement the current thread wait. When await () finishes, the current thread exits the wait, which is the command to close Tomcat, and the Stop () method is executed. wait

Look at a variable, which is used to identify if you want to stop the main thread wait for the identity, when true, it means that you can stop the open and closed Tomcat, this value is set when calling Server.stop ().

Private volatile Boolean stopawait = false;  public void await () {//negative Values-don ' t wait on port-tomcat are embedded or we just don ' t like ports if (
        Port = =-2) {//undocumented yet-for embedding apps that is around, alive.
    Return
            } if (Port==-1) {try {awaitthread = Thread.CurrentThread ();
                while (!stopawait) {try {thread.sleep (10000);
        } catch (Interruptedexception ex) {//Continue and check the flag}}
        } finally {awaitthread = null;
    } return; }//Set up a server sockets to wait on//from a listening port, this port number is the server above us.
    The port number in the XML configuration file try {awaitsocket = new ServerSocket (port, 1, Inetaddress.getbyname (address)); } catch (IOException e) {loG.error ("standardserver.await:create[" + Address + ":" + Port + "]:
        ", e);
    Return

        } try {awaitthread = Thread.CurrentThread (); Loop waiting for a connection and a valid command while (!stopawait) {ServerSocket ServerSocket =
            Awaitsocket;
            if (ServerSocket = = null) {break;
            }//Wait for the next connection socket socket = NULL;
            StringBuilder command = new StringBuilder ();
                try {InputStream stream;
                Long acceptstarttime = System.currenttimemillis ();
                    try {socket = serversocket.accept ();  Socket.setsotimeout (10 * 1000);
                Ten seconds stream = Socket.getinputstream (); } catch (Sockettimeoutexception ste) {//This should never happen but bug 56684 sUggests that//it does.  Log.warn (sm.getstring ("StandardServer.accept.timeout", Long.valueof (System.currenttimemillis ()
                    -Acceptstarttime)), Ste);
                Continue
                            } catch (Accesscontrolexception ace) {log.warn ("standardserver.accept Security Exception:"
                    + Ace.getmessage (), ACE);
                Continue } catch (IOException e) {if (stopawait) {//Wait is aborted with Socket.clo
                    SE () break;
                    } log.error ("StandardServer.await:accept:", e);
                Break }//Read a set of characters from the socket int expected = 1024;  Cut off to avoid DoS attack while (expected < shutdown.length ()) {if (random = =
      Null                  Random = new Random ();
                Expected + = (random.nextint ()% 1024);
                    } while (Expected > 0) {int ch =-1;
                    try {ch = stream.read ();
                        } catch (IOException e) {Log.warn ("StandardServer.await:read:", e);
                    ch =-1;
                        }//Control character or EOF ( -1) terminates loop if (Ch < + | | ch = = 127) {
                    Break
                    } command.append ((char) ch);
                expected--;
                    }} finally {//Close the socket now, we are doing with it try {
                    if (socket! = NULL) {socket.close ();
          }} catch (IOException e) {//Ignore      }}//Match against our command string Boolean match = Command.tostring (). Equa
            LS (shutdown);
                if (match) {Log.info (sm.getstring ("Standardserver.shutdownviaport"));
            Break } else Log.warn ("StandardServer.await:Invalid command" + command.tostring () + "
        ' Received ');
        }} finally {ServerSocket serversocket = Awaitsocket;
        Awaitthread = null;

        Awaitsocket = null; Close the server socket and return if (serversocket! = null) {try {serversocket.c
            Lose (); } catch (IOException e) {//Ignore}}}}

To understand this code, we need to understand a few things. Port and shutdown are the port numbers and shutdown strings of the configuration files mentioned earlier, which are used to listen for the Stop command and what the Stop command is stopawait variable: This initialization is false, After the Server.stop () is executed, it becomes true.

The main purpose of the await () method is to allow the current thread to wait, mainly in three parts when Port is 2, it means that Tomcat is used as a non-standalone servlet container and does not need to be concerned when Port is 1, it periodically loops through the stopawait Whether the variable is true, or true, exits the loop, otherwise the current thread continues to sleep. In other cases (port is positive, when Tomcat acts as a standalone servlet container), the corresponding port is listened to, when the input is received, the corresponding input is obtained, and matches the input to the target shutdown command is consistent, if consistent, then exit, inconsistent, The stopawait value determines whether the wait or exit is continued. At the same time, a Dos attack on the port is considered.

at this point, Tomcat has finished booting, the current thread is non-deamon, a number of deamon threads are being started, those threads are used to receive and process requests from the client, and when the current non-deamon exits, the Deamon thread exits automatically, and Tomcat shuts down

When exiting from await (), execute the Stop () method to close Tomcat. Stop Service

Not on the source, relatively simple, mainly divided into two steps

9. Call the Server.stop () method
10. Inside the Server.stop () method, call Service.stop () and Stopawait () (Set the stopawait variable) to let the main thread exit and perform some exit operations. Stop Server

 public void Stopserver (string[] arguments) {Server s = getserver ();
            if (s = = null) {//Create and execute our digester digester digester = Createstopdigester ();
            File File = ConfigFile (); Try (fileinputstream fis = new FileInputStream (file)) {InputSource is = new Inputsour CE (file. Touri (). Tourl ().
                ToString ());
                Is.setbytestream (FIS);
                Digester.push (this);
            Digester.parse (IS); } catch (Exception e) {log.error ("Catalina.
                Stop: ", e);
            System.exit (1); }} else {//Server object already present.
            Must be running as a service try {s.stop ();
        } catch (Lifecycleexception e) {} return;
        }//Stop the existing server S = Getserver (); if (S.getport () >0) {try (Socket s)Ocket = new Socket (s.getaddress (), S.getport ());
                OutputStream stream = Socket.getoutputstream ()) {String shutdown = S.getshutdown ();
                for (int i = 0; i < shutdown.length (); i++) {Stream.Write (Shutdown.charat (i));
            } stream.flush ();
            } catch (Connectexception CE) {system.exit (1);
            } catch (IOException e) {system.exit (1);
        }} else {system.exit (1); }
    }

The

is primarily in two cases, which correspond to the port number 1 and the port number greater than 0 in the await () method.
1. When the server at this time is not NULL, call Stop ()

directly

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.