Tomcat boot process for springboot

  springboot

Timing diagram 1

图片描述

Timing diagram 2

图片描述

NioEndpoint(Key categories)

/**
     * Start the NIO endpoint, creating acceptor, poller threads.
     */
    @Override
    public void startInternal() throws Exception {

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

            processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getProcessorCache());
            eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                            socketProperties.getEventCache());
            nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                    socketProperties.getBufferPool());

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

            initializeConnectionLatch();

            // Start poller threads
            pollers = new Poller[getPollerThreadCount()];
            for (int i=0; i<pollers.length; i++) {
                pollers[i] = new Poller();
                Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                pollerThread.setPriority(threadPriority);
                pollerThread.setDaemon(true);
                pollerThread.start();
            }

            startAcceptorThreads();
        }
    }

startAcceptorThreads(Thread[http-nio-8080-Acceptor-0,5,main])

protected final void startAcceptorThreads() {
        int count = getAcceptorThreadCount();
        acceptors = new Acceptor[count];

        for (int i = 0; i < count; i++) {
            acceptors[i] = createAcceptor();
            String threadName = getName() + "-Acceptor-" + i;
            acceptors[i].setThreadName(threadName);
            Thread t = new Thread(acceptors[i], threadName);
            t.setPriority(getAcceptorThreadPriority());
            t.setDaemon(getDaemon());
            t.start();
        }
    }

NioEndpoint$Acceptor

// --------------------------------------------------- Acceptor Inner Class
    /**
     * The background thread that listens for incoming TCP/IP connections and
     * hands them off to an appropriate processor.
     */
    protected class Acceptor extends AbstractEndpoint.Acceptor {

        @Override
        public void run() {

            int errorDelay = 0;

            // Loop until we receive a shutdown command
            while (running) {

                // Loop if endpoint is paused
                while (paused && running) {
                    state = AcceptorState.PAUSED;
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }

                if (!running) {
                    break;
                }
                state = AcceptorState.RUNNING;

                try {
                    //if we have reached max connections, wait
                    countUpOrAwaitConnection();

                    SocketChannel socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSock.accept();
                    } catch (IOException ioe) {
                        //we didn't get a socket
                        countDownConnection();
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw ioe;
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;

                    // setSocketOptions() will add channel to the poller
                    // if successful
                    if (running && !paused) {
                        if (!setSocketOptions(socket)) {
                            countDownConnection();
                            closeSocket(socket);
                        }
                    } else {
                        countDownConnection();
                        closeSocket(socket);
                    }
                } catch (SocketTimeoutException sx) {
                    // Ignore: Normal condition
                } catch (IOException x) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), x);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }
            }
            state = AcceptorState.ENDED;
        }
    }

Here I see the familiar code of java network programming that I haven’t seen for a long time.

countUpOrAwaitConnection

protected void countUpOrAwaitConnection() throws InterruptedException {
        if (maxConnections==-1) return;
        LimitLatch latch = connectionLimitLatch;
        if (latch!=null) latch.countUpOrAwait();
    }

Initial value of LimitLatch (maxConnections)

protected LimitLatch initializeConnectionLatch() {
        if (maxConnections==-1) return null;
        if (connectionLimitLatch==null) {
            connectionLimitLatch = new LimitLatch(getMaxConnections());
        }
        return connectionLimitLatch;
    }

Above this value, the request has been waiting since it came in, i.e. the connection is piled up in the accept queue and the service cannot be obtained.

Details of TCP three-way handshake Connection Establishment in socket

图片描述

When the client calls connect, it triggers the connection request and sends SYN J packet to the server, then connect enters the blocking state. The server listens to the connection request, namely receives the SYN J packet, calls the accept function to receive the request and sends SYN K, ACK J+1 to the client, then accept enters the blocking state; After the client receives the SYN K and ACK J+1 from the server, connect returns and confirms the SYN K. When the server receives ACK K+1, accept returns, thus completing the three-way handshake and establishing the connection.

The client’s connect returned for the second time in three-way handshake, while the server’s accept returned for the third time in three-way handshake.

Socket Layer Execution Logic in three-way handshake

三次握手建立TCP连接的流程如下:
    C(Browser)                                    S(www.baidu.com)
 1. CLOSED                                             LISTEN
 2. SYN-SENT    →<SEQ=0><CTL=SYN>              → SYN-RECEIVED
 3. ESTABLISHED← <SEQ=0><ACK=1><CTL=SYN,ACK> ← SYN-RECEIVED
 4. ESTABLISHED→ <SEQ=1><ACK=1><CTL=ACK>      → ESTABLISHED
3-Way Handshake for Connection Synchronization

S calls the listen function of socket to enter listening state; C calls connect function to connect S: [SYN], S calls accept function to accept C’s connection and initiate connection with C direction: [SYN,ACK]. C Send [ACK] to complete three-way handshake, connect function returns; After s receives [ACK] from c, the accept function returns.

图片描述

doc