SpringBootアプリケーションはTomcatを内蔵するプロセスのソースコードの分析を開始します。


Connector起動過程
ConnectorはTomcatが提供するクラスです。

//     Connector       
@Override
protected void startInternal() throws LifecycleException {

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

    setState(LifecycleState.STARTING);

    try {
    	//     
        protocolHandler.start();
    } catch (Exception e) {
        throw new LifecycleException(
                sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
    }
}
springbootはデフォルトでは8080ポートでHTTPサービスを提供しますので、ここではHTTPプロトコル要求を処理するHttp 11 NioProtocolの例です。NIO方式を使ってHTTPプロトコルを処理します。
ConnectorはHTTP要求の受信と処理を自ら行うのではなく、このHttp 11 Nio Protocol protocolHandlerに依頼します。

protocolHandlerはさらにNioEnd pointに処理を依頼します。
AbstractProtocol

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

    endpoint.start();
    monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
            new Runnable() {
                @Override
                public void run() {
                    if (!isPaused()) {
                        startAsyncTimeout();
                    }
                }
            }, 0, 60, TimeUnit.SECONDS);
}
呼び出しチェーン:
  • Connector.start()
  • startInternal()
  • Http 11 NioProtocol protocol Handler.start()
  • Http 11 NioProtocolのstart方法は、ベースクラスAbstractProtocolによって提供されて実現される。これらはすべてtomcatが提供するクラスです。
  • NioEndpoint endpoint.start()
  • startメンバー変数endpoint、NioEnd pointの例です。Http 11 NioProtocol類の例も最終的な処理要求ではありません。具体的にはこれらの要求の処理はNioEndpint endpointに任せています。

    Abstract Endpoint
    
    public final void start() throws Exception {
        if (bindState == BindState.UNBOUND) {
            bindWithCleanup();
            bindState = BindState.BOUND_ON_START;
        }
        startInternal();
    }
    tomcatの3つのモードが表示され、デフォルトではNIOモードが使用されます。
    
    @Override
    public void bind() throws Exception {
        initServerSocket();
    
        setStopLatch(new CountDownLatch(1));
    
        // Initialize SSL if needed
        initialiseSsl();
    
        selectorPool.open(getName());
    }
    
    protected void initServerSocket() throws Exception {
        if (!getUseInheritedChannel()) {
        	//        
            serverSock = ServerSocketChannel.open();
            socketProperties.setProperties(serverSock.socket());
            InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
            //        
            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      
        serverSock.configureBlocking(true); //mimic APR behavior
    }
    serverSocketはブロッキングモードになっていますが、デフォルトではNIOモードを使用していますが、なぜブロッキングモードを設定しますか?
    なぜNIOを使うのですか?BIOのacceptは閉塞方法なので、writeとreadも渋滞しています。新しい接続が来たら、新しいスレッドを作成してこの接続を処理するしかありません。このように、最大の問題は大量の接続を同時に処理することができません。大量の接続によって、多くのスレッドが作られ、多くのスレッドが操作システムを崩壊させやすく、同時に度が高いですが、多くのスレッドが空回りしています。多くの時間がスレッドの走りとスレッドの切り替えに無駄になり、効率も悪いです。
    NIOが誕生しました。
    実際には、接続を処理するための操作は、バックグラウンドスレッドに置かなくてもいいです。バックグラウンドスレッドは接続の確立が遅れている可能性が高いので、メインスレッドに置いたほうがいいです。
    重要な関心事は、接続が確立された後に得られるクライアントとのインタラクティブなそのsocketの動作は、明らかにブロックされていない必要があります。長い接続を処理する時、私達が関心を持っているのは今回の接続の中でデータの読み書きです。
    NioEndpointは遮断モードのServerSocketChanelを使って、遮断して接続が入るのを待っています。acceptの後だけ、この着信したsocket chanelをブロックなしで処理します。
    著者らが指摘したように、ServerSocketChanelを非ブロッキングにすると、すなわち、スレッドは、非ブロッキングモードでaccept()がnullに戻る可能性があるので、入力された接続の有無を常にポーリングしている。
    APR代表Apache Portable Runtime
    Tomcatはsocketを受け取った時、次のように操作しました。


    参照
    https://blog.csdn.net/andy_zhang 2007/articale/details/78641974
    https://stackoverflow.com/questions/23168910/why-tomcats-non-blocking-connector-is-using-a-blocking-socket
    ここで、SpringBootアプリケーションについてTomcatを内蔵したプロセス分析を開始する記事を紹介します。Spring BootにはTomcatを内蔵しています。以前の記事を検索したり、下記の関連記事を見たりしてください。これからもよろしくお願いします。