Tomcat源碼學習第3篇 - Bootstrap的啓動過程

上一篇咱們看了Tomcat中各個組件的init過程,初始化賦值好了,那麼接下來就該輪到start了,話很少說,立刻進入主題~java

1. Bootstrap.start()

經過start方法咱們能夠看到他是經過反射調用了 Catalina.start() 方法,按F7跳到這個類裏面看一下。web

public void start() throws Exception {
    if (catalinaDaemon == null) {
        init();
    }
    // 經過反射調用 Catalina.start() 方法
    Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
    method.invoke(catalinaDaemon, (Object [])null);
}

image

2. Catalina.start()

進來一看,又是熟悉的套娃風格,還得繼續往裏面跳轉多線程

image

3. LifecycleBase.start()

仍是這個熟悉的組件生命週期類,看到這裏就彷彿看到告終局,確定是跟initInternal這個方法同樣一層層嵌套進去,讓咱們走起~app

image

4. StandardServer.startInternal()

以前咱們有所過在一個Tomcat中是能夠有多個service的,因此這裏須要遍歷全部的service分別讓各自啓動起來socket

image

server.xml文件中再給他配置一個<Service>標籤便可,如圖所示:async

image

5. StandardService.startInternal()

開始進入正題了,在這個方法中咱們能夠看到它分別作了如下操做:ide

  1. 容器的啓動:engine.start()
  2. 鏈接器的啓動:connector.start()
protected void startInternal() throws LifecycleException {
    if(log.isInfoEnabled())
        log.info(sm.getString("standardService.start.name", this.name));
    setState(LifecycleState.STARTING);

    // 這裏首先啓動咱們定義的容器 engine
    if (engine != null) {
        synchronized (engine) {
            // 啓動 engine 子容器
            engine.start();
        }
    }

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

    mapperListener.start();

    // Start our defined Connectors second
    synchronized (connectorsLock) {
        for (Connector connector: connectors) {
            try {
                // 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);
            }
        }
    }
}

6. StandardEngine.startInternal()

這裏直接調用的ContainerBase.startInternal方法實現下屬組件的啓動this

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();
}

7. ContainerBase.startInternal()

這裏使用的是線程池的方式,若是有多個Host,那麼就能夠多個線程並行實例化Host,加快Tomcat啓動速度spa

protected synchronized void startInternal() throws LifecycleException {
    // 啓動下屬容器
    logger = null;
    getLogger();
    Cluster cluster = getClusterInternal();
    if (cluster instanceof Lifecycle) {
        ((Lifecycle) cluster).start();
    }
    Realm realm = getRealmInternal();
    if (realm instanceof Lifecycle) {
        ((Lifecycle) realm).start();
    }

    // 查找並啓動子容器,Host 在初始化階段後仍是不完整的,須要繼續封裝,把容器關係維護完整
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<>();
    for (Container child : children) {
        results.add(startStopExecutor.submit(new StartChild(child)));
    }

    MultiThrowable multiThrowable = null;

    for (Future<Void> result : results) {
        try {
            result.get();
        } catch (Throwable e) {
            log.error(sm.getString("containerBase.threadedStartFailed"), e);
            if (multiThrowable == null) {
                multiThrowable = new MultiThrowable();
            }
            multiThrowable.add(e);
        }

    }
    if (multiThrowable != null) {
        throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                                     multiThrowable.getThrowable());
    }

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

    // 設置容器生命週期狀態
    setState(LifecycleState.STARTING);

    // Start our thread
    threadStart();
}

[圖片上傳失敗...(image-bc6c2d-1616772543941)]線程

image

8. StandardHost.startInternal()

protected synchronized void startInternal() throws LifecycleException {

    // Set error report valve
    String errorValve = getErrorReportValveClass();
    if ((errorValve != null) && (!errorValve.equals(""))) {
        try {
            boolean found = false;
            Valve[] valves = getPipeline().getValves();
            for (Valve valve : valves) {
                if (errorValve.equals(valve.getClass().getName())) {
                    found = true;
                    break;
                }
            }
            if(!found) {
                Valve valve =
                    (Valve) Class.forName(errorValve).getConstructor().newInstance();
                getPipeline().addValve(valve);
            }
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            log.error(sm.getString(
                    "standardHost.invalidErrorReportValveClass",
                    errorValve), t);
        }
    }
    super.startInternal();
}

Host的實例化,是經過設置生命週期狀態來進行促發生命週期事件fireLifecycleEvent來執行後續工做的。

  1. deployApps:處理 host下多個應用
  2. deployDirectories:處理host下面以目錄方式部署的(results.add(),這裏也是以多線程的方式並行執行的)
  3. host.addChild():這時猜觸發context實例核心內容
  4. context:具體讀取web.xml封裝wrapper過程使用事件驅動交給ContextConfig(它也是一個事件監聽器)

image

image

image

image

image

9. MapperListener.startInternal()

public void startInternal() throws LifecycleException {

        setState(LifecycleState.STARTING);
        // 獲得 engine 容器
        Engine engine = service.getContainer();
        if (engine == null) {
            return;
        }
        // 找到默認主機
        findDefaultHost();
        // 爲當前容器以及子容器添加監聽器
        addListeners(engine);
        // 註冊engine下全部的host
        Container[] conHosts = engine.findChildren();
        for (Container conHost : conHosts) {
            Host host = (Host) conHost;
            if (!LifecycleState.NEW.equals(host.getState())) {
                // 註冊上下文和包裝器
                registerHost(host);
            }
        }
    }

10. Connector.startInternal()

截至到這裏,容器的註冊與啓動已經完成了,接下來到鏈接器的啓動了

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 {
        protocolHandler.start();
    } catch (Exception e) {
        throw new LifecycleException(
            sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
    }
}

11. AbstractProtocol.start()

這裏對 EndPoint進行初始化

public void start() throws Exception {
    if (getLog().isInfoEnabled()) {
        getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
    }

    endpoint.start();

    // Start timeout thread
    asyncTimeout = new AsyncTimeout();
    Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
    int priority = endpoint.getThreadPriority();
    if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
        priority = Thread.NORM_PRIORITY;
    }
    timeoutThread.setPriority(priority);
    timeoutThread.setDaemon(true);
    timeoutThread.start();
}

image

12. AbstractEndpoint.start()

public final void start() throws Exception {
    if (bindState == BindState.UNBOUND) {
        bind();
        bindState = BindState.BOUND_ON_START;
    }
    startInternal();
}

13. NioEndpoint.bind()

public void bind() throws Exception {
    if (!getUseInheritedChannel()) {
        // 獲取 nio 通道 channel
        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
        // 綁定端口,但還沒有使用 accept 獲取客戶端鏈接
        serverSock.socket().bind(addr,getAcceptCount());
    } else {
        // Retrieve the channel provided by the OS
        Channel ic = System.inheritedChannel();
        if (ic instanceof ServerSocketChannel) {
            serverSock = (ServerSocketChannel) ic;
        }
        if (serverSock == null) {
            throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
        }
    }
    serverSock.configureBlocking(true); //mimic APR behavior

    // Initialize thread count defaults for acceptor, poller
    if (acceptorThreadCount == 0) {
        // FIXME: Doesn't seem to work that well with multiple accept threads
        acceptorThreadCount = 1;
    }
    if (pollerThreadCount <= 0) {
        //minimum one poller thread
        pollerThreadCount = 1;
    }
    setStopLatch(new CountDownLatch(pollerThreadCount));

    // Initialize SSL if needed
    initialiseSsl();

    selectorPool.open();
}

14. NioEndpoint.startInternal()

這裏經過startAcceptorThreads啓動Accepter線程,該線程用於接收新的Socket鏈接

image

image

總結

image

相關文章
相關標籤/搜索