`
pi88dian88
  • 浏览: 40065 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

tomcat 启动流程

阅读更多
刚开始的时候,只是想导入源码直接看,但是水平不够,有些流程不知道怎么走了,皱眉, 于是搭建了调试的环境,边调试边学习。 搭建调试的环境可以参考下面的链接:

http://blog.csdn.net/teabook00/article/details/5620023

 

下面先粗略的过下整个流程。

1, tomcat的启动是从Bootstrap开始, 下面是main()的主要代码

 

  public static void main(String args[]) {
        if (daemon == null) {
            daemon = new Bootstrap();
            try {
                daemon.init();
            } catch (Throwable t) {
                t.printStackTrace();
                return;
            }
        }

        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 {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }

    }

 通过反射的方式,分别调用Catalina的load()和start()的方法。

 

2, load方法主要完成组件的装配以及组件的初始化。 先看下面的load方法,

 

//因为需要调用多个方法,这里将load方法的主要代码合并到了一起 
public void load() {
	Digester digester = new Digester();
        // 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/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
        digester.addSetProperties("Server/Service");
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");

        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");
        
        // Add RuleSets for nested elements
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
        digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
        digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));

        // When the 'engine' is found, set the parentClassLoader.
        digester.addRule("Server/Service/Engine",
                         new SetParentClassLoaderRule(parentClassLoader));
        digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/"));

        try {
            file = configFile(); //读取conf/server.xml
            inputStream = new FileInputStream(file);
            inputSource = new InputSource("file://" + file.getAbsolutePath());
        } catch (Exception e) {
        }

        try {
            inputSource.setByteStream(inputStream);
            digester.parse(inputSource);
        } catch (Exception e) {
            return;
        }
        getServer().initialize();
    }

 

 tomcat使用SAX来解析conf/server.xml, 以Service为例,来了解tomcat如何完成组件的组装。

 

(1) 下面是server.xml的配置文件

 

<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <Listener className="org.apache.catalina.core.JasperListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/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 name="Catalina" defaultHost="localhost">
      <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">
      </Host>
    </Engine>
  </Service>
</Server>

 

 

(2) Digester 继承 DefaultHandler,作为server.xml解析的handler,下面是startElment 和 endElement的主要代码

 

public void startElement(String namespaceURI, String localName,
                             String qName, Attributes list)
            throws SAXException {
        // Fire "begin" events for all relevant rules
        List rules = getRules().match(namespaceURI, match);
        matches.push(rules);
        if ((rules != null) && (rules.size() > 0)) {
            for (int i = 0; i < rules.size(); i++) {
                Rule rule = (Rule) rules.get(i);
                rule.begin(namespaceURI, name, list);
            }
        } 

    }

public void endElement(String namespaceURI, String localName,
                           String qName) throws SAXException {
        // Fire "body" events for all relevant rules
        List rules = (List) matches.pop();
        if ((rules != null) && (rules.size() > 0)) {
            String bodyText = this.bodyText.toString();
            for (int i = 0; i < rules.size(); i++) {
                Rule rule = (Rule) rules.get(i);
                rule.body(namespaceURI, name, bodyText);
            }
        } 
        // Fire "end" events for all relevant rules in reverse order
        if (rules != null) {
            for (int i = 0; i < rules.size(); i++) {
                int j = (rules.size() - i) - 1;
                Rule rule = (Rule) rules.get(j);
                rule.end(namespaceURI, name);
            }
        }
    }

 (2) 调用addObjectCreate的方法,创建了ObjectCreateRule,下面是ObjectCreateRule的方法,begin方法主要根据className来创建一个实例,即创建了StandardService

 public void begin(Attributes attributes) throws Exception {
		// Identify the name of the class to instantiate
		String realClassName = className;
		if (attributeName != null) {
			String value = attributes.getValue(attributeName);
			if (value != null) {
				realClassName = value;
			}
		}
		// Instantiate the new object and push it on the context stack
		Class clazz = digester.getClassLoader().loadClass(realClassName);
		Object instance = clazz.newInstance();
		digester.push(instance);
	}

	public void end() throws Exception {
		Object top = digester.pop();
	}

(3)调用addSetProperties方法,创建SetPropertiesRule,下面是SetPropertiesRule的begin方法,主要用来初始化参数(根据server.xml中的配置)

public void begin(Attributes attributes) throws Exception {
        // Populate the corresponding properties of the top object
        Object top = digester.peek();
        
        for (int i = 0; i < attributes.getLength(); i++) {
            String name = attributes.getLocalName(i);
            if ("".equals(name)) {
                name = attributes.getQName(i);
            }
            String value = attributes.getValue(i);
            IntrospectionUtils.setProperty(top, name, value) 
        }

    }

 (4) 调用setNextRule方法,创建SetNextRule,下面是SetNextRule的end方法

 public void end() throws Exception {
        // Identify the objects to be used
        Object child = digester.peek(0);
        Object parent = digester.peek(1);

        // Call the specified method
        IntrospectionUtils.callMethod1(parent, methodName,
                child, paramType, digester.getClassLoader());
    }

 其中,child为Service,parent为Server,methodName为addService,这样就完成了Server/Service的组装。

 

 3, 调用getServer().initialize() 方法初始化StandardServer对象,下面是StandardServer的initialize方法

 

 public void initialize()
        throws LifecycleException 
    {
        if (initialized) {
                log.info(sm.getString("standardServer.initialize.initialized"));
            return;
        }
        lifecycle.fireLifecycleEvent(INIT_EVENT, null); 
        initialized = true;

        if( oname==null ) {
            try {
                oname=new ObjectName( "Catalina:type=Server");
                Registry.getRegistry(null, null)
                    .registerComponent(this, oname, null );
            } catch (Exception e) {
                log.error("Error registering ",e);
            }
        }
        
        // Register global String cache
        try {
            ObjectName oname2 = 
                new ObjectName(oname.getDomain() + ":type=StringCache");
            Registry.getRegistry(null, null)
                .registerComponent(new StringCache(), oname2, null );
        } catch (Exception e) {
            log.error("Error registering ",e);
        }

        // Initialize our defined Services
        for (int i = 0; i < services.length; i++) {
            services[i].initialize();
        }
    }
 使用JMX管理Server对象,然后调用Service的initialize方法。后面StandardEngine, Connector等的初始化方法都相似。

 

 

4, 调用Catalina的start方法,主要代码如下

 

        // Start the new server
        if (getServer() instanceof Lifecycle) {
            try {
                ((Lifecycle) getServer()).start();
            } catch (LifecycleException e) {
                log.error("Catalina.start: ", e);
            }
        }
 5,调用StandardServer的start方法,主要代码如下

 

 

public void start() throws LifecycleException {

        // Validate and update our current component state
        if (started) {
            log.debug(sm.getString("standardServer.start.started"));
            return;
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);

        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Services
        synchronized (services) {
            for (int i = 0; i < services.length; i++) {
                if (services[i] instanceof Lifecycle)
                    ((Lifecycle) services[i]).start();
            }
        }

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    }
 6, 调用StandardService的start方法,代码如下

 

 

public void start() throws LifecycleException {
        // Validate and update our current component state
        if (started) {
            return;
        }
        
        if( ! initialized )
            init(); 
        lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        // Start our defined Container first
        if (container != null) {
            synchronized (container) {
                if (container instanceof Lifecycle) {
                    ((Lifecycle) container).start();
                }
            }
        }

        synchronized (executors) {
            for ( int i=0; i<executors.size(); i++ ) {
                executors.get(i).start();
            }
        }

        // Start our defined Connectors second
        synchronized (connectors) {
            for (int i = 0; i < connectors.length; i++) {
                try {
                    ((Lifecycle) connectors[i]).start();
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connectors[i]), e);
                }
            }
        }
        
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }
 7, 调用StandardEngine的start方法,主要代码如下

 

 

 public void start() throws LifecycleException {
        if( started ) {
            return;
        }
        if( !initialized ) {
            init();
        }
        // Standard container startup
        super.start();
    }
 StandardEngine继承ContainerBase,下面是ContainerBase的start方法

 

 

public synchronized void start() throws LifecycleException {
        // Validate and update our current component state
        if (started) {
            return;
        }
        started = true;

        // Start our subordinate components, if any
        if ((logger != null) && (logger instanceof Lifecycle))
            ((Lifecycle) logger).start();
        if ((manager != null) && (manager instanceof Lifecycle))
            ((Lifecycle) manager).start();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        if ((realm != null) && (realm instanceof Lifecycle))
            ((Lifecycle) realm).start();
        if ((resources != null) && (resources instanceof Lifecycle))
            ((Lifecycle) resources).start();

        // Start our child containers, if any  //StandardHost
        Container children[] = findChildren();
        for (int i = 0; i < children.length; i++) {
            if (children[i] instanceof Lifecycle)
                ((Lifecycle) children[i]).start();
        }

        // Start the Valves in our pipeline (including the basic), if any
        if (pipeline instanceof Lifecycle)
            ((Lifecycle) pipeline).start();

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(START_EVENT, null);

        // Start our thread
        threadStart();

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);

    }
 在前面的组件装配过程中,通过digester.addSetNext("Server/Service/Engine/Host", "addChild",  "org.apache.catalina.Container") 方法,将StandardHost与StandardEngine组装。因此findChildren得到StandardHost对象,执行其start方法。

 

 

8, 调用StandardHost的start方法,代码如下

 

public synchronized void start() throws LifecycleException {
        if( started ) {
            return;
        }
        if( ! initialized )
            init();
        // Set error report valve
        if ((errorReportValveClass != null)
            && (!errorReportValveClass.equals(""))) {
            try {
                boolean found = false;
                if(errorReportValveObjectName != null) {
                    ObjectName[] names = 
                        ((StandardPipeline)pipeline).getValveObjectNames();
                    for (int i=0; !found && i<names.length; i++)
                        if(errorReportValveObjectName.equals(names[i]))
                            found = true ;
                    }
                    if(!found) {          	
                        Valve valve = (Valve) Class.forName(errorReportValveClass)
                        .newInstance();
                        addValve(valve);
                        errorReportValveObjectName = ((ValveBase)valve).getObjectName() ;
                    }
            } catch (Throwable t) {
            }
        }
        super.start();

    }
 同样,StandardHost继承ContainerBase(代码见上面的ContainerBase),在调用lifecycle.fireLifecycleEvent(START_EVENT, null)时,会调用先前注册的LifecycleListener, 注册方法在前面的组装过程中,代码如下

 

 

 digester.addRule(prefix + "Host",
                         new LifecycleListenerRule
                         ("org.apache.catalina.startup.HostConfig",
                          "hostConfigClass"));
 

 

9, 调用HostConfig的lifecycleEvent方法

 

// Identify the host we are associated with
        try {
            host = (Host) event.getLifecycle();
            if (host instanceof StandardHost) {
                setDeployXML(((StandardHost) host).isDeployXML());
                setUnpackWARs(((StandardHost) host).isUnpackWARs());
                setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware());
                setXmlValidation(((StandardHost) host).getXmlValidation());
            }
        } catch (ClassCastException e) {
            log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
            return;
        }

        // Process the event that has occurred
        if (event.getType().equals(Lifecycle.START_EVENT))
            start();
        else if (event.getType().equals(Lifecycle.STOP_EVENT))
            stop();
 在start方法中,会调用deployApps方法,具体如下

 

 

 protected void deployApps() {

        File appBase = appBase();
        File configBase = configBase();
        String[] filteredAppPaths = filterAppPaths(appBase.list());
        // Deploy XML descriptors from configBase
        deployDescriptors(configBase, configBase.list());
        // Deploy WARs, and loop if additional descriptors are found
        deployWARs(appBase, filteredAppPaths);
        // Deploy expanded folders
        deployDirectories(appBase, filteredAppPaths);
        
    }
 

 

10, 调用deployDescriptor方法,代码如下

 

  protected void deployDescriptor(String contextPath, File contextXml, String file) {
        if (deploymentExists(contextPath)) {
            return;
        }
        
        DeployedApplication deployedApp = new DeployedApplication(contextPath);        
        Context context = null;
        try {
            synchronized (digester) {
                try {
                    context = (Context) digester.parse(contextXml);
                    if (context == null) {
                        log.error(sm.getString("hostConfig.deployDescriptor.error",
                                file));
                        return;
                    }
                } finally {
                    digester.reset();
                }
            }
            if (context instanceof Lifecycle) {
                Class clazz = Class.forName(host.getConfigClass());
                LifecycleListener listener =
                    (LifecycleListener) clazz.newInstance();
                ((Lifecycle) context).addLifecycleListener(listener);
            }
            context.setConfigFile(contextXml.getAbsolutePath());
            context.setPath(contextPath);
            host.addChild(context);
            ...
    }
 

 

11, StandardHost的addChild方法会调用addChildInternal,代码如下

 

 private void addChildInternal(Container child) {
        synchronized(children) {
            if (children.get(child.getName()) != null)
                throw new IllegalArgumentException("addChild:  Child name '" +
                                                   child.getName() +
                                                   "' is not unique");
            child.setParent(this);  // May throw IAE
            children.put(child.getName(), child);

            // Start child
            if (started && startChildren && (child instanceof Lifecycle)) {
                boolean success = false;
                try {
                    ((Lifecycle) child).start();
                    success = true;
                } catch (LifecycleException e) {
                    log.error("ContainerBase.addChild: start: ", e);
                    throw new IllegalStateException
                        ("ContainerBase.addChild: start: " + e);
                } finally {
                    if (!success) {
                        children.remove(child.getName());
                    }
                }
            }

            fireContainerEvent(ADD_CHILD_EVENT, child);
        }

    }
 由第十步可知,方法的参数为StandardContext对象,因此,会调用StandardContext的start方法。

 

 

12,调用StandardContext的start方法

 

 public synchronized void start() throws LifecycleException {
        ....
        try {
            if (ok) {                                
                // Start our child containers, if any
                Container children[] = findChildren();
                for (int i = 0; i < children.length; i++) {
                    if (children[i] instanceof Lifecycle)
                        ((Lifecycle) children[i]).start();
                }

                // Start the Valves in our pipeline (including the basic),
                // if any
                if (pipeline instanceof Lifecycle) {
                    ((Lifecycle) pipeline).start();
                }
                
                // Notify our interested LifecycleListeners
                lifecycle.fireLifecycleEvent(START_EVENT, null);                                
            }
        } 
       ....
    }
 在调用lifecycle.fireLifecycleEvent(START_EVENT, null)时,会调用先前注册的LifecycleListener, 注册方法在前面的组装过程中,代码如下

 

 

   digester.addRule(prefix + "Context",
                             new LifecycleListenerRule
                                 ("org.apache.catalina.startup.ContextConfig",
                                  "configClass"));
 
13,调用ContextConfig的lifecycleEvent方法, 代码如下
 if (event.getType().equals(Lifecycle.START_EVENT)) {
            start();
        } else if (event.getType().equals(StandardContext.BEFORE_START_EVENT)) {
            beforeStart();
        } else if (event.getType().equals(StandardContext.AFTER_START_EVENT)) {
            // Restore docBase for management tools
            if (originalDocBase != null) {
                String docBase = context.getDocBase();
                context.setDocBase(originalDocBase);
                originalDocBase = docBase;
            }
        } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
            if (originalDocBase != null) {
                String docBase = context.getDocBase();
                context.setDocBase(originalDocBase);
                originalDocBase = docBase;
            }
            stop();
        } else if (event.getType().equals(Lifecycle.INIT_EVENT)) {
            init();
        } else if (event.getType().equals(Lifecycle.DESTROY_EVENT)) {
            destroy();
        }
 在start方法中,最终会调用processDefaultWebConfig方法,主要代码如下
protected void processDefaultWebConfig(Digester digester, InputStream stream, 
            InputSource source) {
        // Process the default web.xml file
        synchronized (digester) {
            try {
                source.setByteStream(stream);
                
                if (context instanceof StandardContext)
                    ((StandardContext) context).setReplaceWelcomeFiles(true);
                digester.setClassLoader(this.getClass().getClassLoader());
                digester.setUseContextClassLoader(false);
                digester.push(context);
                digester.setErrorHandler(new ContextErrorHandler());
                digester.parse(source);
                if (parseException != null) {
                    ok = false;
                }
                ....
            } finally {
                digester.reset();
                parseException = null;
                try {
                    if (stream != null) {
                        stream.close();
                    }
                } catch (IOException e) {
                    log.error(sm.getString("contextConfig.defaultClose"), e);
                }
            }
        }
    }
 上面的方法通过解析 conf/web.xml来加载org.apache.catalina.servlets.DefaultServlet 和 org.apache.jasper.servlet.JspServlet。

 

 

 

 

 

 

 

 

 

  • 大小: 125.2 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics