• 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方法的剩余部分。

  • 相关阅读:
    Unity 自制Cubemap及使用
    Exp4
    实验一 密码引擎-2-OpenEuler-OpenSSL测试
    实验一 密码引擎-3-电子钥匙功能测试
    实验一 密码引擎-1-OpenEuler-OpenSSL编译
    实验一 密码引擎-0-OpenEuler ECS构建
    商用密码企业调研(必做)
    exp3
    exp2
    exp1
  • 原文地址:https://www.cnblogs.com/coldridgeValley/p/5631614.html
Copyright © 2020-2023  润新知