Tomcat启动过程源码分析五

前言

上一篇文章中我们讨论了Bootstrap类中main方法中涉及到的load方法,今天这篇文章我们来查看下start方法。

/**
 * Start the Catalina daemon.
 */
public void start()
    throws Exception {
    if( catalinaDaemon==null ) init();

    Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
    method.invoke(catalinaDaemon, (Object [])null);

}

具体代码就不分析了,可以看出start方法使用了反射调用了catalinaDaemonstart方法,而catalinaDeamon是类Catalina的实例,直接查看Catalina类的start方法

Catalina类
/**
 * Start a new server instance.
 */
public void start() {
		//...判断代码
    // Start the new server
    try {
		//11111
        getServer().start();
    } catch (LifecycleException e) {
        log.fatal(sm.getString("catalina.serverStartFail"), e);
        try {
            getServer().destroy();
        } catch (LifecycleException e1) {
            log.debug("destroy() failed for failed Server ", e1);
        }
        return;
    }

    long t2 = System.nanoTime();
    if(log.isInfoEnabled()) {
        log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
    }
	
	//22222222
    // Register shutdown hook
    if (useShutdownHook) {
        if (shutdownHook == null) {
            shutdownHook = new CatalinaShutdownHook();
        }
        Runtime.getRuntime().addShutdownHook(shutdownHook);

        // If JULI is being used, disable JULI's shutdown hook since
        // shutdown hooks run in parallel and log messages may be lost
        // if JULI's hook completes before the CatalinaShutdownHook()
        LogManager logManager = LogManager.getLogManager();
        if (logManager instanceof ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    false);
        }
    }
	//333333333333
    if (await) {
        await();
        stop();
    }
}

可以看出来除了一些判断意外,start方法基本分成了3个步骤,我们依次来查看。

第一步

在第一步调用了getServer().start()方法,其实也就是调用了StandardServerstart方法,我们查看StandardServer类发现,他并没有start方法,继续查看其父类,发现其父类包含了LifecycleBase,其中实现了start方法,而在start方法中又调用了startInternal方法,所以看到这里大概也明白了,start这个方法类似init方法,也使用了模版设计模式,所以我们直接看StandardServer类的startInternal方法就可以了。

@Override
protected void startInternal() throws LifecycleException {

    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    setState(LifecycleState.STARTING);

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

除了调用了globalNamingResourcesstart方法,还调用了本身Servicestart方法,由于globalNamingResources是一个组件,我们这里暂时不介绍,有兴趣可以自己跟源码查看,我们来看下servicestart方法, 也就是StandardServicestartInternal方法。

 @Override
protected void startInternal() throws LifecycleException {

    if(log.isInfoEnabled())
        log.info(sm.getString("standardService.start.name", this.name));
    setState(LifecycleState.STARTING);

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

    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }

    // Start our defined Connectors second
    synchronized (connectorsLock) {
        for (Connector connector: connectors) {
            try {
				//222222
                // If it has already failed, don't try and start it
                if (connector.getState() != LifecycleState.FAILED) {
                    connector.start();
                }
            } catch (Exception e) {
                log.error(sm.getString(
                        "standardService.connector.startFailed",
                        connector), e);
            }
        }
    }
}

可以看到StandardServicestartInternal方法主要做了2个动作,第一个是调用了Containerstart方法,第二个是调用了Connectorstart方法,我们先看Containerstart方法,也就是对应实现类StandardEnginestartInternal方法。

    @Override
protected synchronized void startInternal() throws LifecycleException {
    
    // Log our server identification information
    if(log.isInfoEnabled())
        log.info( "Starting Servlet Engine: " + ServerInfo.getServerInfo());

    // Standard container startup
    super.startInternal();
}

查看类继承关系

public class StandardEngine extends ContainerBase implements Engine 

查看类ContainerBase中的startInternal方法

 @Override
protected synchronized void startInternal() throws LifecycleException {

	//启动各种组件
    // Start our subordinate components, if any
    if ((loader != null) && (loader instanceof Lifecycle))
        ((Lifecycle) loader).start();
    logger = null;
    getLogger();
    if ((manager != null) && (manager instanceof Lifecycle))
        ((Lifecycle) manager).start();
    if ((cluster != null) && (cluster instanceof Lifecycle))
        ((Lifecycle) cluster).start();
    Realm realm = getRealmInternal();
    if ((realm != null) && (realm instanceof Lifecycle))
        ((Lifecycle) realm).start();
    if ((resources != null) && (resources instanceof Lifecycle))
        ((Lifecycle) resources).start();

	//获取子容器,启动所有的子容器
	//子容器主要是 Host 对应实现类 StandardHost 调用其startInternal方法
    // Start our child containers, if any
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<Future<Void>>();
    for (int i = 0; i < children.length; i++) {
        results.add(startStopExecutor.submit(new StartChild(children[i])));
    }

    boolean fail = false;
    for (Future<Void> result : results) {
        try {
            result.get();
        } catch (Exception e) {
            log.error(sm.getString("containerBase.threadedStartFailed"), e);
            fail = true;
        }

    }
    if (fail) {
        throw new LifecycleException(
                sm.getString("containerBase.threadedStartFailed"));
    }
	//启动pipeline 组件
    // Start the Valves in our pipeline (including the basic), if any
    if (pipeline instanceof Lifecycle)
        ((Lifecycle) pipeline).start();


    setState(LifecycleState.STARTING);
	//启动container 后台线程
    // Start our thread
    threadStart();

}

从代码的注释中可以清楚的看到StandardEnginestartInternal方法都做了什么,我们继续查看ConnectorstartInternal方法。

    @Override
protected void startInternal() throws LifecycleException {

    // Validate settings before starting
    if (getPort() < 0) {
        throw new LifecycleException(sm.getString(
                "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
    }

    setState(LifecycleState.STARTING);

    try {
		//11 
        protocolHandler.start();
    } catch (Exception e) {
        String errPrefix = "";
        if(this.service != null) {
            errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
        }

        throw new LifecycleException
            (errPrefix + " " + sm.getString
             ("coyoteConnector.protocolHandlerStartFailed"), e);
    }
	//2
    mapperListener.start();
}

我们可以看到ConnectorstartInternal方法主要做了两件事,第一件是调用了变量protocolHandlerstart方法,第二件事是调用了mapperListenerstart方法,我们主要看下protocolHandler的调用。

类似init方法讲解中提到的,protocolHandler有两个实例分别代表http请求和ajb请求,我们主要看对应http请求,也就是实例Http11ProtocolstartInternal方法。我们查看类Http11Protocol发现其中并无start方法相关,查看其父类AbstractProtocol发现其中的start方法。

 @Override
public void start() throws Exception {
    if (getLog().isInfoEnabled())
        getLog().info(sm.getString("abstractProtocolHandler.start",
                getName()));
    try {
        endpoint.start();
    } catch (Exception ex) {
        getLog().error(sm.getString("abstractProtocolHandler.startError",
                getName()), ex);
        throw ex;
    }
}

其中调用了endpointstart方法。而在Http11Protocol类的构造方法中可以看到

    public Http11Protocol() {
    endpoint = new JIoEndpoint();
    cHandler = new Http11ConnectionHandler(this);
    ((JIoEndpoint) endpoint).setHandler(cHandler);
    setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
    setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
    setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
}

endpoint是类JIoEndpoint的实例,我们继续查看JIoEndpoint

   @Override
public void startInternal() throws Exception {

    if (!running) {
        running = true;
        paused = false;

        // Create worker collection
        if (getExecutor() == null) {
            createExecutor();
        }

        initializeConnectionLatch();

        startAcceptorThreads();

        // Start async timeout thread
        Thread timeoutThread = new Thread(new AsyncTimeout(),
                getName() + "-AsyncTimeout");
        timeoutThread.setPriority(threadPriority);
        timeoutThread.setDaemon(true);
        timeoutThread.start();
    }
}

看到这里Connectorstart方法就结束了,StandardServicestart方法也结束了。

在文章的最开始我们提到了Catalina类的start方法,上面跟源码分析了那么多其实一直是分析getServer().start(),下一篇文章我们继续分析Catalina类的start方法的剩余部分。

posted @ 2016-06-30 23:43  coldridgeValley  阅读(1265)  评论(0编辑  收藏  举报