1. 程式人生 > >深入理解Tomcat系列之三 Connector

深入理解Tomcat系列之三 Connector

                     

前言

Connector是Tomcat的聯結器,其主要任務是負責處理瀏覽器傳送過來的請求,並建立一個Request和Response的物件用於和瀏覽器交換資料,然後產生一個執行緒用於處理請求,Connector會把Request和Response物件傳遞給該執行緒,該執行緒的具體的處理過程是Container容器的事了。執行過程分為以下幾個步驟

  1. 例項化Connector,構造一個Connector物件
  2. 呼叫Connector的initIntenal方法,初始化Connetor
  3. 呼叫ProtocolHanlder的init方法,完成ProtocolHanlder的初始化。這個過程包括了建立執行緒池並建立一個執行緒處理瀏覽器請求
  4. 呼叫Connector的startIntenal方法,啟動Connector
  5. 呼叫ProtocolHandler的start方法,啟動Protocolhanlder
  6. 呼叫MapperListener的start方法,啟動監聽器程式

為了對Connector的執行過程有一個大概的印象,可以參考下面的序列圖:

Connector啟動過程

注意:由於Tomcat還支援AJP協議,但為了簡化,我畫的這個序列圖是基於Http協議的,這也是我們在Web開發中接觸最多的協議了。

在深入Connector之前我們先看看Connector類的結構:

Connector屬性
Connector部分方法

既然是處理瀏覽器請求,那麼需要支援http協議,在Tomcat中有兩種協議處理器:HTTP/1.1與AJP/1.3協議處理器。在server.xml中已經指明tomcat所支援的兩種協議:

程式碼清單3-1:

    <Connector port="8080" protocol="HTTP/1.1"               connectionTimeout="20000"               redirectPort="8443" />    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
  • 1
  • 2
  • 3
  • 4

在tomcat中是怎麼樣分別處理這兩種協議的呢,我們可以ProtocolHanlder類中找到答案:

ProtocolHanlder協議處理器

圖中被選中的就是Tomcat預設使用協議處理器,其實現過程與Java標準Socket程式設計是一樣的,在tomcat中可以使用Connetor類的setProtocol方法,看看原始碼就知道了:

程式碼清單3-2:

    public void setProtocol(String protocol) {        if (AprLifecycleListener.isAprAvailable()) {            if ("HTTP/1.1".equals(protocol)) {                setProtocolHandlerClassName                    ("org.apache.coyote.http11.Http11AprProtocol");            } else if ("AJP/1.3".equals(protocol)) {                setProtocolHandlerClassName                    ("org.apache.coyote.ajp.AjpAprProtocol");            } else if (protocol != null) {                setProtocolHandlerClassName(protocol);            } else {                setProtocolHandlerClassName                    ("org.apache.coyote.http11.Http11AprProtocol");            }        } else {            if ("HTTP/1.1".equals(protocol)) {                setProtocolHandlerClassName                    ("org.apache.coyote.http11.Http11Protocol");            } else if ("AJP/1.3".equals(protocol)) {                setProtocolHandlerClassName                    ("org.apache.coyote.ajp.AjpProtocol");            } else if (protocol != null) {                setProtocolHandlerClassName(protocol);            }        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

從第2個if子句的最後一個else可以知道tomcat預設使用的是http1.1協議。
我們再看看Connector的初始化過程:

程式碼清單3-3:

    @Override    protected void initInternal() throws LifecycleException {        super.initInternal();        // Initialize adapter        adapter = new CoyoteAdapter(this);        protocolHandler.setAdapter(adapter);        // Make sure parseBodyMethodsSet has a default        if( null == parseBodyMethodsSet ) {            setParseBodyMethods(getParseBodyMethods());        }        if (protocolHandler.isAprRequired() &&                !AprLifecycleListener.isAprAvailable()) {            throw new LifecycleException(                    sm.getString("coyoteConnector.protocolHandlerNoApr",                            getProtocolHandlerClassName()));        }        try {            protocolHandler.init();        } catch (Exception e) {            throw new LifecycleException                (sm.getString                 ("coyoteConnector.protocolHandlerInitializationFailed"), e);        }        // Initialize mapper listener        mapperListener.init();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

從這段程式碼中可以看到:首先呼叫父類org.apache.catalina.util.LifecycleMBeanBase的初始化方法,然後建立一個Adapter,然後設定protocolHanlder(協議處理器)的Adapter,同時判斷傳過來的請求的請求方法(比如get或者post),如果沒有指明請求方法,預設使用post處理,然後呼叫protocolHanlder的初始化方法,最後呼叫mapperListener的初始化方法,而mapperListener的初始化方法呼叫的是org.apache.catalina.util.LifecycleBase的init方法,我們重點關注protocolHanlder的初始化方法,具體是實現在AbstractProtocol抽象類中,其直接子類有AbstractAjpProtocol和AbstractHttp11Protocol,分別對應的是兩種不同的處理協議,所以協議處理器的初始化方法是在其子抽象類(實現ProtocolHanlder介面的抽象類)來實現的,這裡看看AbstractHttp11Protocol的初始化方法:

程式碼清單3-4:

    @Override    public void init() throws Exception {        if (getLog().isInfoEnabled())            getLog().info(sm.getString("abstractProtocolHandler.init",                    getName()));        if (oname == null) {            // Component not pre-registered so register it            oname = createObjectName();            if (oname != null) {                Registry.getRegistry(null, null).registerComponent(this, oname,                    null);            }        }        if (this.domain != null) {            try {                tpOname = new ObjectName(domain + ":" +                        "type=ThreadPool,name=" + getName());                Registry.getRegistry(null, null).registerComponent(endpoint,                        tpOname, null);            } catch (Exception e) {                getLog().error(sm.getString(                        "abstractProtocolHandler.mbeanRegistrationFailed",                        tpOname, getName()), e);            }            rgOname=new ObjectName(domain +                    ":type=GlobalRequestProcessor,name=" + getName());            Registry.getRegistry(null, null).registerComponent(                    getHandler().getGlobal(), rgOname, null );        }        String endpointName = getName();        endpoint.setName(endpointName.substring(1, endpointName.length()-1));        try {            endpoint.init();        } catch (Exception ex) {            getLog().error(sm.getString("abstractProtocolHandler.initError",                    getName()), ex);            throw ex;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

打斷點除錯可以知道oname的值是Tomcat:type=ProtocolHandler,port=auto-1,address="127.0.0.1",tpOname是Tomcat:type=ProtocolHandler,port=auto-1,address="127.0.0.1",rOname是Tomcat:type=GlobalRequestProcessor,name="http-bio-127.0.0.1-auto-1",我們重點關注endpoint的init方法,主要完成以下幾個過程:

  1. 設定執行緒接收數和最大連線數
  2. 建立執行緒池,啟動監聽的執行緒監聽使用者請求
  3. 啟動一個執行緒處理請求

初始化完成Connector就可以啟動了,啟動階段呼叫startInternal方法:

程式碼清單3-5:

    @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 {            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);        }        mapperListener.start();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

可以看出Connector呼叫protocolHandler.start()方法,繼續看看這個方法的原始碼:

程式碼清單3-6:

    @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;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

這個方法又呼叫了endpoint.start()方法:

程式碼清單3-7:

    public final void start() throws Exception {        if (bindState == BindState.UNBOUND) {            bind();            bindState = BindState.BOUND_ON_START;        }        startInternal();    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然後又呼叫了org.apache.tomcat.util.net.AbstractEndpoint.startInternal()方法:

程式碼清單3-8:

    @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();        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  1. 設定執行緒接收數和最大連線數
  2. 建立執行緒池,啟動監聽的執行緒監聽使用者請求
  3. 啟動一個執行緒處理非同步請求

這裡啟動了一個非同步執行緒處理請求,這個非同步執行緒是如何執行的呢?

程式碼清單3-9:

    /**     * Async timeout thread     */    protected class AsyncTimeout implements Runnable {        /**         * The background thread that checks async requests and fires the         * timeout if there has been no activity.         */        @Override        public void run() {            // Loop until we receive a shutdown command            while (running) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    // Ignore                }                long now = System.currentTimeMillis();                Iterator<SocketWrapper<Socket>> sockets =                    waitingRequests.iterator();                while (sockets.hasNext()) {                    SocketWrapper<Socket> socket = sockets.next();                    long access = socket.getLastAccess();                    if (socket.getTimeout() > 0 &&                            (now-access)>socket.getTimeout()) {                        processSocketAsync(socket,SocketStatus.TIMEOUT);                    }                }                // Loop if endpoint is paused                while (paused && running) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        // Ignore                    }                }            }        }    }    //processSocket    public boolean processSocketAsync(SocketWrapper<Socket> socket,            SocketStatus status) {        try {            synchronized (socket) {                if (waitingRequests.remove(socket)) {                    SocketProcessor proc = new SocketProcessor(socket,status);                    ClassLoader loader = Thread.currentThread().getContextClassLoader();                    try {                        //threads should not be created by the webapp classloader                        if (Constants.IS_SECURITY_ENABLED) {                            PrivilegedAction<Void> pa = new PrivilegedSetTccl(                                    getClass().getClassLoader());                            AccessController.doPrivileged(pa);                        } else {                            Thread.currentThread().setContextClassLoader(                                    getClass().getClassLoader());                        }                        // During shutdown, executor may be null - avoid NPE                        if (!running) {                            return false;                        }                        getExecutor().execute(proc);                        //TODO gotta catch RejectedExecutionException and properly handle it                    } finally {                        if (Constants.IS_SECURITY_ENABLED) {                            PrivilegedAction<Void> pa = new PrivilegedSetTccl(loader);                            AccessController.doPrivileged(pa);                        } else {                            Thread.currentThread().setContextClassLoader(loader);                        }                    }                }            }        } catch (Throwable t) {            ExceptionUtils.handleThrowable(t);            // This means we got an OOM or similar creating a thread, or that            // the pool and its queue are full            log.error(sm.getString("endpoint.process.fail"), t);            return false;        }        return true;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

org.apache.tomcat.util.net.JIoEndpoint.SocketProcessor的職責是把具體的請求處理過程委派給org.apache.tomcat.util.net.JIoEndpoint.Handler,然後根據handler返回的不同SocketState,來決定是否關閉連線或者進行下一輪處理。

程式碼清單3-10:

public void run() {            boolean launch = false;            synchronized (socket) {                try {                    SocketState state = SocketState.OPEN;                    try {                        // SSL handshake                        serverSocketFactory.handshake(socket.getSocket());                    } catch (Throwable t) {                        ExceptionUtils.handleThrowable(t);                        if (log.isDebugEnabled()) {                            log.debug(sm.getString("endpoint.err.handshake"), t);                        }                        // Tell to close the socket                        state = SocketState.CLOSED;                    }                    if ((state != SocketState.CLOSED)) {                        if (status == null) {                            state = handler.process(socket, SocketStatus.OPEN_READ);                        } else {                            state = handler.process(socket,status);                        }                    }                    if (state == SocketState.CLOSED) {                        // Close socket                        if (log.isTraceEnabled()) {                            log.trace("Closing socket:"+socket);                        }                        countDownConnection();                        try {                            socket.getSocket().close();                        } catch (IOException e) {                            // Ignore                        }                    } else if (state == SocketState.OPEN ||                            state == SocketState.UPGRADING ||                            state == SocketState.UPGRADING_TOMCAT  ||                            state == SocketState.UPGRADED){                        socket.setKeptAlive(true);                        socket.access();                        launch = true;                    } else if (state == SocketState.LONG) {                        socket.access();                        waitingRequests.add(socket);                    }                } finally {                    if (launch) {                        try {                            getExecutor().execute(new SocketProcessor(socket, SocketStatus.OPEN_READ));                        } catch (RejectedExecutionException x) {                            log.warn("Socket reprocessing request was rejected for:"+socket,x);                            try {                                //unable to handle connection at this time                                handler.process(socket, SocketStatus.DISCONNECT);                            } finally {                                countDownConnection();                            }                        } catch (NullPointerException npe) {                            if (running) {                                log.error(sm.getString("endpoint.launch.fail"),                                        npe);                            }                        }                    }                }            }            socket = null;            // Finish up this request        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

其中的process方法主要完成對request的解析,包括請求頭、請求行和請求體
程式碼清單3-11:

    //process method of org.apache.coyote.http11.AbstractHttp11Processor<S>.HttpProcessor extends org.apache.coyote.http11.AbstractHttp11Processor<S>    @Override    public SocketState process(SocketWrapper<S> socketWrapper)        throws IOException {        RequestInfo rp = request.getRequestProcessor();        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);        // Setting up the I/O        setSocketWrapper(socketWrapper);        getInputBuffer().init(socketWrapper, endpoint);        getOutputBuffer().init(socketWrapper, endpoint);        // Flags        error = false;        keepAlive = true;        comet = false;        openSocket = false;        sendfileInProgress = false;        readComplete = true;        if (endpoint.getUsePolling()) {            keptAlive = false;        } else {            keptAlive = socketWrapper.isKeptAlive();        }        if (disableKeepAlive()) {            socketWrapper.setKeepAliveLeft(0);        }        while (!error && keepAlive && !comet && !isAsync() &&                upgradeInbound == null &&                httpUpgradeHandler == null && !endpoint.isPaused()) {            // Parsing the request header            try {                setRequestLineReadTimeout();                if (!getInputBuffer().parseRequestLine(keptAlive)) {                    if (handleIncompleteRequestLineRead()) {                        break;                    }                }                if (endpoint.isPaused()) {                    // 503 - Service unavailable                    response.setStatus(503);                    error = true;                } else {                    // Make sure that connectors that are non-blocking during                    // header processing (NIO) only set the start time the first                    // time a request is processed.                    if (request.getStartTime() < 0) {                        request.setStartTime(System.currentTimeMillis());                    }                    keptAlive = true;                    // Set this every time in case limit has been changed via JMX                    request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());                    // Currently only NIO will ever return false here                    if (!getInputBuffer().parseHeaders()) {                        // We've read part of the request, don't recycle it                        // instead associate it with the socket                        openSocket = true;                        readComplete = false;                        break;                    }                    if (!disableUploadTimeout) {                        setSocketTimeout(connectionUploadTimeout);                    }                }            } catch (IOException e) {                if (getLog().isDebugEnabled()) {                    getLog().debug(                            sm.getString("http11processor.header.parse"), e);                }                error = true;                break;            } catch (Throwable t) {                ExceptionUtils.handleThrowable(t);                UserDataHelper.Mode logMode = userDataHelper.getNextMode();                if (logMode != null) {                    String message = sm.getString(                            "http11processor.header.parse");                    switch (logMode) {                        case INFO_THEN_DEBUG:                            message += sm.getString(                                    "http11processor.fallToDebug");                            //$FALL-THROUGH$                        case INFO:                            getLog().info(message);                            break;                        case DEBUG:                            getLog().debug(message);                    }                }                // 400 - Bad Request                response.setStatus(400);                adapter.log(request, response, 0);                error = true;            }            if (!error) {                // Setting up filters, and parse some request headers                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);                try {                    prepareRequest();                } catch (Throwable t) {                    ExceptionUtils.handleThrowable(t);                    if (getLog().isDebugEnabled()) {                        getLog().debug(sm.getString(                                "http11processor.request.prepare"), t);                    }                    // 400 - Internal Server Error                    response.setStatus(400);                    adapter.log(request, response, 0);                    error = true;                }            }            if (maxKeepAliveRequests == 1) {                keepAlive = false;            } else if (maxKeepAliveRequests > 0 &&                    socketWrapper.decrementKeepAlive() <= 0) {                keepAlive = false;            }            // Process the request in the adapter            if (!error) {                try {                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);                    adapter.service(request, response);                    if(keepAlive && !error) { // Avoid checking twice.                        error = response.getErrorException() != null ||                                (!isAsync() &&                                statusDropsConnection(response.getStatus()));                    }                    setCometTimeouts(socketWrapper);                } catch (InterruptedIOException e) {                    error = true;                } catch (HeadersTooLargeException e) {                    error = true;                    // The response should not have been committed but check it                    // anyway to be safe                    if (!response.isCommitted()) {                        response.reset();                        response.setStatus(500);                        response.setHeader("Connection", "close");                    }                } catch (Throwable t) {                    ExceptionUtils.handleThrowable(t);                    getLog().error(sm.getString(                            "http11processor.request.process"), t);                    // 500 - Internal Server Error                    response.setStatus(500);                    adapter.log(request, response, 0);                    error = true;                }            }            // Finish the handling of the request            rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);            if (!isAsync() && !comet) {                if (error) {                    getInputBuffer().setSwallowInput(false);                }                if (response.getStatus() < 200 || response.getStatus() > 299) {                    if (expectation) {                        // Client sent Expect: 100-continue but received a                        // non-2xx response. Disable keep-alive (if enabled) to                        // ensure the connection is closed. Some clients may                        // still send the body, some may send the next request.                        // No way to differentiate, so close the connection to                        // force the client to send the next request.                        getInputBuffer().setSwallowInput(false);                        keepAlive = false;                    }                }                endRequest();            }            rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);            // If there was an error, make sure the request is counted as            // and error, and update the statistics counter            if (error) {                response.setStatus(500);            }            request.updateCounters();            if (!isAsync() && !comet || error) {                getInputBuffer().nextRequest();                getOutputBuffer().nextRequest();            }            if (!disableUploadTimeout) {                if(endpoint.getSoTimeout() > 0) {                    setSocketTimeout(endpoint.getSoTimeout());                } else {                    setSocketTimeout(0);                }            }            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);            if (breakKeepAliveLoop(socketWrapper)) {                break;            }        }        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196

首先在Http11Processor的process方法裡,會先從socket裡讀取http請求資料,並解析請求頭,構造Request物件和Response物件,然後呼叫Adapter.service()方法。Adapter.service()完成請求行以及請求體的解析,並把解析出來的資訊封裝到Request和Response物件中,Adapter(確切說是org.apache.catalina.connector.CoyoteAdapter)是connector和container的橋樑,經過這一步,請求就從connector傳遞到container裡了,Adapter.service()方法之後便將封裝了Request以及Response物件的Socket傳給Container容器了。
要注意的是:最先處理請求的Request是org.apache.coyote.Request型別,這是一個Tomcat中一個輕量級物件,完成基本的請求處理後很容易被JVM回收,那為什麼不直接交給Connector.Request物件處理呢?由於後者是Servlet容器真正傳遞的物件其完成的職責比前者複雜,這裡使用org.apache.coyote.Request主要減輕後者的任務負擔,出於效能考慮才這麼設計。
具體service方法清單如下:

程式碼清單3-12:

@Overridepublic void service(org.apache.coyote.Request req,                      org.apache.coyote.Response res)      throws Exception {      Request request = (Request) req.getNote(ADAPTER_NOTES);      Response response = (Response) res.getNote(ADAPTER_NOTES);      if (request == null) {          // Create objects          request = connector.createRequest();          request.setCoyoteRequest(req);          response = connector.createResponse();          response.setCoyoteResponse(res);          // Link objects          request.setResponse(response);          response.setRequest(request);          // Set as notes          req.setNote(ADAPTER_NOTES, request);          res.setNote(ADAPTER_NOTES, response);          // Set query string encoding          req.getParameters().setQueryStringEncoding              (connector.getURIEncoding());      }      if (connector.getXpoweredBy()) {          response.addHeader("X-Powered-By", POWERED_BY);      }      boolean comet = false;      boolean async = false;      try { // Parse and set Catalina and configuration //specific          // request parameters          req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());          //postParseRequest方法把CoyoteRequest轉換為Connector.Request物件          //後一型別的物件才是在Tomcat容器流轉時真正傳遞的物件          boolean postParseSuccess = postParseRequest(req, request, res, response);          if (postParseSuccess) {              //check valves if we support async              request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());    // 呼叫Container容器的invoke方法,把請求交給Container容器              connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);              if (request.isComet()) {                  if (!response.isClosed() && !response.isError()) {                      if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) {                          // Invoke a read event right away if there are available bytes                          if (event(req, res, SocketStatus.OPEN_READ)) {                              comet = true;                              res.action(ActionCode.COMET_BEGIN, null);                          }                      } else {                          comet = true;                          res.action(ActionCode.COMET_BEGIN, null);                      }                  } else {                      // Clear the filter chain, as otherwise it will not be reset elsewhere                      // since this is a Comet request                      request.setFilterChain(null);                  }              }          }          AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext();          if (asyncConImpl != null) {              async = true;          } else if (!comet) {              request.finishRequest();              response.finishResponse();              if (postParseSuccess &&                      request.getMappingData().context != null) {                  ((Context) request.getMappingData().context).logAccess(                          request, response,                          System.currentTimeMillis() - req.getStartTime(),                          false);              }              req.action(ActionCode.POST_REQUEST , null);          }      } catch (IOException e) {          // Ignore      } finally {         //ignore      }  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79

connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);這句