美文网首页
Tomcat源码分析(一):启动

Tomcat源码分析(一):启动

作者: walker_liu_fei | 来源:发表于2017-03-23 10:10 被阅读0次

    Tomcat作为一个Java应用, 其启动一定是需要一个main() 作为入口。而这个main() 函数就在类Bootstrap内部

    Main 函数

      /**
         * Main method and entry point when starting Tomcat via the provided
         * scripts.
         *
         * @param args Command line arguments to be processed
         */
        public static void main(String args[]) {
    
            if (daemon == null) {
                // Don't set daemon until init() has completed
                Bootstrap bootstrap = new Bootstrap();
                try {
                    bootstrap.init();
                } catch (Throwable t) {
                    handleThrowable(t);
                    t.printStackTrace();
                    return;
                }
                daemon = bootstrap;
            } 
    .................................省略代码......................
    
                if (command.equals("startd")) {
                    args[args.length - 1] = "start";
                    daemon.load(args);
                    daemon.start();
                } 
    .................................省略代码......................
        }
    

    可以看出对于第一次启动来讲,main函数主要是做了新建一个Bootstrap类,并调用其init()方法

      /**
         * Initialize daemon.
         * @throws Exception Fatal initialization error
         */
        public void init() throws Exception {
    
            initClassLoaders();
    
            Thread.currentThread().setContextClassLoader(catalinaLoader);
    
            SecurityClassLoad.securityClassLoad(catalinaLoader);
    
            // Load our startup class and call its process() method
            if (log.isDebugEnabled())
                log.debug("Loading startup class");
            // 通过反射找到一个Catalina类,并通过反射调用其startUp()方法
            Class<?> startupClass =
                catalinaLoader.loadClass
                ("org.apache.catalina.startup.Catalina");
            Object startupInstance = startupClass.newInstance();
            ........................省略代码.......................
             this.catalinaDaemon = startupInstance;
    
        }
    

    从上面代码可以看出,Bootstrap 的init方法通过反射新建了一个Catalina类,并将这个类作为Boostrap的属性

        public void start()
            throws Exception {
            if( catalinaDaemon==null ) init();
    
            Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
            method.invoke(catalinaDaemon, (Object [])null);
    
        }
    

    再来看一下Boostrapstart()方法。可以看出来。它也是通过反射来调起Catalina的start()方法。

    catalina的start() 方法又调用了其load()方法,load 方法又调用了 其createStartDigester()方法

    public void start() {
    
            if (getServer() == null) {
                load();
            }
            . ......
    }
    

    对于createStartDigester(),

     /**
         * Create and configure the Digester we will be using for startup.
         * @return the main digester to parse server.xml
         */
        protected Digester createStartDigester() {
            long t1=System.currentTimeMillis();
            // Initialize the digester
            Digester digester = new Digester();
            digester.setValidating(false);
            digester.setRulesValidation(true);
            HashMap<Class<?>, List<String>> fakeAttributes = new HashMap<>();
            ArrayList<String> attrs = new ArrayList<>();
            attrs.add("className");
            fakeAttributes.put(Object.class, attrs);
            digester.setFakeAttributes(fakeAttributes);
            digester.setUseContextClassLoader(true);
    
            // 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.NamingResourcesImpl");
            digester.addSetProperties("Server/GlobalNamingResources");
            digester.addSetNext("Server/GlobalNamingResources",
                                "setGlobalNamingResources",
                                "org.apache.catalina.deploy.NamingResourcesImpl");
    
            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", "sslImplementationName", "protocol"}));
            digester.addSetNext("Server/Service/Connector",
                                "addConnector",
                                "org.apache.catalina.connector.Connector");
    
            digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
                                     "org.apache.tomcat.util.net.SSLHostConfig");
            digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
            digester.addSetNext("Server/Service/Connector/SSLHostConfig",
                    "addSslHostConfig",
                    "org.apache.tomcat.util.net.SSLHostConfig");
    
            digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
                             new CertificateCreateRule());
            digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
                             new SetAllPropertiesRule(new String[]{"type"}));
            digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
                                "addCertificate",
                                "org.apache.tomcat.util.net.SSLHostConfigCertificate");
    
            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");
    
            digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
                                      null, // MUST be specified in the element
                                      "className");
            digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
            digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
                                "addUpgradeProtocol",
                                "org.apache.coyote.UpgradeProtocol");
    
            // 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/");
    
            long t2=System.currentTimeMillis();
            if (log.isDebugEnabled()) {
                log.debug("Digester for server.xml created " + ( t2-t1 ));
            }
            return (digester);
    
        }
    

    从源码中可以看到,digester对server.xml设置的标签动作有5种调用:

    • addObjectCreate:遇到起始标签的元素,初始化一个实例对象入栈
    • addSetProperties:遇到某个属性名,使用setter来赋值
    • addSetNext:遇到结束标签的元素,调用相应的方法
    • addRule:调用rule的begin 、body、end、finish方法来解析xml,入栈和出栈给对象赋值
    • addRuleSet:调用addRuleInstances来解析xml标签

    从这些规则和xml中可以看到,Calatina的Server对象是StandardServer。StandardService包含了多个Connector(xml中有2个connector)和一个StandardEngine Container。StandardEngine包含了一个Host Container。

    相关文章

      网友评论

          本文标题:Tomcat源码分析(一):启动

          本文链接:https://www.haomeiwen.com/subject/wqoonttx.html