JavaWeb學習之——Tomcat篇Connector

概述

        Tomcat最底層是使用Socket來進行鏈接的,而Connector的做用就是將接受到的請求轉換爲Request和Response。Request和Response是按照HTTP協議來封裝的,封裝完成後就交給Container進行處理。Container處理完成後又返回給Connector,由Connector返給客戶端前端

Connector的結構

        Connector主要是經過ProtocolHandler來處理請求的。不用的ProtocolHandler表明不一樣的鏈接類型。例如Http11Protocal使用普通的socket(同步處理),http11NioProtocal使用的NioSocket來連接。ProtocolHandler裏面有3個很重要的組件:java

  1. Endpoint:處理最底層的Socket連接(一串字符流)
  2. Processor:用戶將Endpoint收到的內容封裝成Requst(也就是須要解析HTTP協議)
  3. Adapter將請求適配到合適的Sevlet容器

ProtocolHandler

<!-- 定義一個Connector,在8080端口箭頭HTTP的請求 -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
   
<!-- 定義一個Connector,在8009端口箭頭AJP的請求 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

在server.xml中就有Connector的配置。圖中配置了監聽HTTP請求和AJP請求apache

ProtocolHandler有一個抽象實現類AbstractProtocal,下面有3個子類,分別是對Ajp,Http,spdy協議的實現服務器

  • Ajp(apache JServ Protocol),Apache的定向包協議,主要用於前端服務器(如Apache)之間的通訊,他是長鏈接。
  • Http:略
  • Spdy: 是google開發的協議,效率比Http搞,但使用不普遍

在Connector中默認是使用org.apache.coyote.http11.Http11NioProtocol。app

Endpoint

Endpoint用於處理具體的鏈接和數據傳輸,實現是比較複雜的。NioEndpoint集成AnstractEndpoint,AnstractEndpoint也是一個模板類,例如start()方法在AnstractEndpoint中,其中bind()方法由子類去實現socket

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

NioEndpoint的bind()方法就是初始化ServerSocketChannel和Selectorgoogle

public void bind() throws Exception {

        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
        serverSock.socket().bind(addr,getBacklog());
        serverSock.configureBlocking(true); //mimic APR behavior
        serverSock.socket().setSoTimeout(getSocketProperties().getSoTimeout());

        // 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;
        }
        stopLatch = new CountDownLatch(pollerThreadCount);

        // Initialize SSL if needed
        initialiseSsl();

        selectorPool.open();
    }

啓動是在startInternal()方法中,主要作了2個事情,初始化Poller線程和Accept線程,Accept負責接收Socket請求,而後具體的處理方法是在Poller線程中。(Accept和Poller是內部類)spa

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

Processor

主要用於處理應用層協議(如HTTP),分別由3個基本協議對應3個基本的抽象類線程

Adapter

Adapter只有一個實現類,就是CoyoteAdapter類。code

  • 把org.apache.coyote包下的Request和Response封裝爲org.apache.catalina.connector的Request和Response
  • 從Serivce中的Container獲取第一個管道,而後調用管道的invoker方法(管道能夠理解爲一個過濾鏈,最後會調用StandardWrapperValue來處理Filter和Servlet)
相關文章
相關標籤/搜索