Tomcat source code Catalina

Source: Internet
Author: User
Catalina initializes each component and starts each component.
This article describes how Bootstrap starts Catalina. Let's take a look at the role of Catalina:
1. Catalina loads server. xml through the digester class, instantiates various components in server. XML, and assigns values to these instances (this class is done by extending SAX ).
2. Call the start method of the server to enable the server component. The server will spread the start component at the first level so that each component is enabled from here.

3. initialize the namespace (Tomcat uses the JNDI technology. For example, if the database connection pool is configured in server. XML, the JNDI is used ). Finally, system. Out and system. Err are packaged.

The focus here is the process of parsing server. xml by digester. Let's take a look at the start method:

Public void start () {// some judgments, logs, server hook functions, and other codes are excluded here ...... if (getserver () = NULL) {load ();}...... getserver (). start (); If (await) {await (); stop ();}}

According to the first if statement, we can know that the server is instantiated using the load method. After the load method is executed, start the server. The logic is very simple. Enter the load method:

Public void load () {// This method is too long. I kicked off some code digester = createstartdigester (); inputsource = NULL; inputstream = NULL; file file = NULL; try {// get Sever. xml configuration file = configfile (); inputstream = new fileinputstream (File); inputsource = new inputsource (file. touri (). tourl (). tostring ();} catch (exception e) {If (log. isdebugenabled () {log. debug (SM. getstring ("ca Talina. configfail ", file), e) ;}// spread the corresponding Sever. XML to Digester and parse it by digester. Inputsource. setbytestream (inputstream); // This method is very important. It places itself, the Catalina object, into a stack of the digester object, after the XML file is parsed to instantiate the server, // The Catalina object from the stack will call its setserver method to set Catalina. server properties. The service attribute in server is also set in this form. Digester. Push (this); digester. parse (inputsource); // After the server is instantiated, the server. Catalina attribute is set. Here Catalina and server are two-way associated. Getserver (). setcatalina (this); // The system. Out and system. Err initstreams (); getserver (). INIT ();}

If you want to figure out how digester loads server. xml and instantiate each component, you may enter the digester. parse (inputsource) method, but this method
Cannot tell you the key content. Let's see what digester is like:
Public class digester extends defaulthandler2
Defaulthandler2 is under the sax extension package. If you are not familiar with sax, you must first understand sax. Otherwise, it is very difficult to see the source code of Catalina. Let's take a look at
The first line of code digester = createstartdigester (); enter the createstartdigester method:

   /**     * Create and configure the Digester we will be using for startup.     */    protected Digester createStartDigester() {                Digester digester = new Digester();        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");        //Executor        digester.addObjectCreate("Server/Service/Executor",                         "org.apache.catalina.core.StandardThreadExecutor",                         "className");        digester.addSetProperties("Server/Service/Executor");        digester.addSetNext("Server/Service/Executor",                            "addExecutor",                            "org.apache.catalina.Executor");        digester.addRule("Server/Service/Connector",                         new ConnectorCreateRule());        digester.addRule("Server/Service/Connector",                         new SetAllPropertiesRule(new String[]{"executor"}));        digester.addSetNext("Server/Service/Connector",                            "addConnector",                            "org.apache.catalina.connector.Connector");        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/Host/"));        addClusterRuleSet(digester, "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));        addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");        return (digester);    }

Looking at these parameters carefully, the node names in the XML document all have corresponding classes, such as the Server Node object org. Apache. Catalina. Core. standardserver.

When digester instantiates a server, it instantiates its sub-class standerserver.

Enter the addobjectcreate method:

public void addObjectCreate(String pattern, String className,                                String attributeName) {        addRule(pattern,                new ObjectCreateRule(className, attributeName));    }

Every time you call the Add * method, a rule subclass is mapped to pattern. addsetproperties and addsetnext map a rule subclass to pattern.
This ing is stored in rulesbase. cache:

public class RulesBase implements Rules {    protected HashMap<String,List<Rule>> cache =        new HashMap<String,List<Rule>>();}

From this data structure, we can know that the complete name of each node corresponds to a list set of rule. Let's see how rule is defined:
public abstract class Rule {    public Digester getDigester() {        return (this.digester);    }    public void begin(String namespace, String name, Attributes attributes)        throws Exception {        begin(attributes);    }    public void end(String namespace, String name)        throws Exception {        end();    }}

Begin and end are their core methods (some sub-classes may not have some of them, so they are important to illustrate the XML parsing process ). Here we want to explain: digster first defines multiple rules for each node in XML. As mentioned above, degister inherits from defaulthandler2 and overwrites its startdocument (), startelement (), enddocument () endelement () and other methods. Degister internally defines a member variable reader of the xmlreader type, and transmits itself as a member variable reader of the contenthandler and dtdhandler type to itself. When parsing XML, reader calls back the callback methods such as startdocument (), startelement (), enddocument (), and endelement () inherited by digster from defaulthandler2. The callback method of the Rule class corresponding to the current node is called. Now let's take the server initialization as an example: in the createstartdigester () method mentioned above, three rules are added for the server:
   digester.addObjectCreate("Server",                                 "org.apache.catalina.core.StandardServer",                                 "className");        digester.addSetProperties("Server");        digester.addSetNext("Server",                            "setServer",                            "org.apache.catalina.Server");

The three methods create three rule classes, objectcreaterule, setpropertiesrule, and setnextrule. These three classes are used to create a specified class, assign the attributes on the XML tag to the modified class, and assign the class to its parent class. After these three classes are created, they are added to the rulesbase. cache mentioned above in a map with the "server" as the key. When the reader class parses XML to the Start Node of the <Server> label, the startelement () method is called, and a series of values such as the node name and attribute value of the current node are passed to the modification method. The method internally obtains the list of corresponding rule class rule objects by the full name of the node, and calls the begin method of the rule object one by one. Take the objectcreaterule rule corresponding to the server as an example:
    public void begin(String namespace, String name, Attributes attributes)            throws Exception {        Class<?> clazz = digester.getClassLoader().loadClass(realClassName);        Object instance = clazz.newInstance();        digester.push(instance);    }

The instance corresponding to the server is created (the Instance name is org. Apache. Catalina. Core. standardserver or the value of the attribute classname object) and placed on the top of a stack named stack attribute in digest. In the preceding load method, digester pushes the current class object, namely the Catalina object, to the stack. At this time, Catalina should be at the bottom of the stack because there is no data in the previous stack. The server label is server. the first tag of XML. At this time, it is parsed to its start tag and the begin method of the objectcreaterule rule with its object is called to initialize the server object and then push it to the stack, at this time, the stack has two elements: Catalina at the bottom of the stack and server at the top of the stack. After the start method of objectcreaterule ends, it will continue to call the start method of setpropertiesrule. This class is to assign the attribute value of the tag to the object created above, the first step of its begin method is to get the object from the stack, then, assign the attribute values on the tag to the object, such as the port and shutdown attributes in <server port = "8005" shutdown = "shutdown">. The last is the setnextrule class. This class only has one end method called when the end label of </Server> is met. The source code of this method is as follows:
    @Override    public void end(String namespace, String name) throws Exception {        Object child = digester.peek(0);        Object parent = digester.peek(1);        if (digester.log.isDebugEnabled()) {            if (parent == null) {                digester.log.debug("[SetNextRule]{" + digester.match +                        "} Call [NULL PARENT]." +                        methodName + "(" + child + ")");            } else {                digester.log.debug("[SetNextRule]{" + digester.match +                        "} Call " + parent.getClass().getName() + "." +                        methodName + "(" + child + ")");            }        }        IntrospectionUtils.callMethod1(parent, methodName,                child, paramType, digester.getClassLoader());                    }
Before calling this method, the member variable stack of degister has already pushed and pop several objects. Each time the tag starts parsing, the object is created and pushed to the stack. After the Tag ends, it pops out from the stack. Because the <Server> label is a top-level label, the server object is first created and pushed to the stack (Catalina has been at the bottom of the stack), and finally pop out, therefore, when the end tag </Server> is parsed, the stack is still two elements, the server is at the top of the stack, and the Catalina is at the bottom of the stack. Object child = digester. Peek (0); object parent = digester. Peek (1); the elements at the top and bottom of the stack are extracted respectively. The parsing of server. XML is not a good description, and its relationship is a bit complicated. Remember that each level of server. xml tag corresponds to a tomcat component. The tag wrapped by the outer tag is an attribute of the outer tag. For example, serveice is an attribute of the server. When XML is parsed, it calls the parsing rules of the corresponding node based on the current event (start, or end), creates an object, and completes the association between objects through stacks.


Tomcat source code Catalina

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.