Tomcat聯結器執行過程(原始碼閱讀)

小鞅發表於2016-05-01

:為了單純的瞭解聯結器執行過程,與別的元件相關部分程式碼被註釋了,該篇文章只是簡單的對重點程式碼進行解釋,理論知識可以參考《how tomcat works》這本書,感覺還是不錯的。

1.啟動(這是自己寫的一個簡單啟動程式碼)

private static void start() {
HttpConnector connector = new HttpConnector();
connector.start();
    }
 

2.HttpConnecter類中的start()方法

 public void start() {
        // Validate and update our current state
        // if (started)
        // throw new
        // LifecycleException(sm.getString("httpConnector.alreadyStarted"));
        threadName = "HttpConnector[" + port + "]";
        // lifecycle.fireLifecycleEvent(START_EVENT, null);
        started = true;

        //啟動當前執行緒
        threadStart();

        // Create the specified minimum number of processors
        while (curProcessors < minProcessors) {
            if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
                break;
            HttpProcessor processor = newProcessor();
            //將當前執行緒建立處理器加入處理器池中
            recycle(processor);
        }
    }
 

3.HttpConnecter類中threadStart()方法

private void threadStart() {

        // log(sm.getString("httpConnector.starting"));
        // 啟動當前的connector的執行緒
        thread = new Thread(this, threadName);
        // 設定為守護執行緒
        thread.setDaemon(true);
        thread.start();

    }
 

4.HttpConnector類的run()方法

public void run() {

        // Loop until we receive a shutdown command
        while (!stopped) {
            // Accept the next incoming connection from the server socket
            Socket socket = null;
            try {

                socket = serverSocket.accept();

                // 設定連結超時(假設設定為10分鐘)以後,如果客戶端socket和服務端socket連結以後10中以後會自動斷開
                // tcp連結,預設是一支不設定超時就是一直連結的
                if (connectionTimeout > 0)
                    socket.setSoTimeout(connectionTimeout);
                // 決定是否使用nagle演算法,也就是將小資料包先不傳送,附加在下一個資料包後面傳送過來
                socket.setTcpNoDelay(tcpNoDelay);
            } catch (AccessControlException ace) {
                log("socket accept security exception", ace);
                continue;
            } catch (IOException e) {

                try {
                    // If reopening fails, exit
                    synchronized (threadSync) {
                        if (started && !stopped)
                            log("accept error: ", e);
                        if (!stopped) {

                            serverSocket.close();
                            // if (debug >= 3)
                            // log("run: Reopening server socket");
                            // serverSocket = open();
                        }
                    }

                } catch (IOException ioe) {
                    log("socket reopen, io problem: ", ioe);
                    break;
                } catch (KeyStoreException kse) {
                    log("socket reopen, keystore problem: ", kse);
                    break;
                } catch (NoSuchAlgorithmException nsae) {
                    log("socket reopen, keystore algorithm problem: ", nsae);
                    break;
                } catch (CertificateException ce) {
                    log("socket reopen, certificate problem: ", ce);
                    break;
                } catch (UnrecoverableKeyException uke) {
                    log("socket reopen, unrecoverable key: ", uke);
                    break;
                } catch (KeyManagementException kme) {
                    log("socket reopen, key management problem: ", kme);
                    break;
                }

                continue;
            }

            // Hand this socket off to an appropriate processor
            // 啟動完一個proccessor執行緒以後,先讓它們處於wait狀態,因為此時並沒有需要處理的請求。
            HttpProcessor processor = createProcessor();
            if (processor == null) {
                try {
                    // log(sm.getString("httpConnector.noProcessor"));
                    socket.close();
                } catch (IOException e) {
                    ;
                }
                continue;
            }
            // 將tcp連線封裝的socket物件分配給Processor處理
            processor.assign(socket);

            // The processor will recycle itself when it finishes
            synchronized (threadSync) {
                threadSync.notifyAll();
            }
        }
    }
 

5.HttpConnector類的assign()方法

synchronized void assign(Socket socket) {


            // Wait for the Processor to get the previous Socket,預設為false
            while (available) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }

            // Store the newly available Socket and notify our thread
            this.socket = socket;
            //通知processor的執行緒現在可以啟動了
            available = true;
            //通知自己的在等待的執行緒可以啟用了,他們會自己去競爭資源
            //因為是用當前processor的物件來進行wait的(),因此就是通知當前processor的執行緒執行,而不是所有
            //在等待processor執行緒
            notifyAll();

            if ((debug >= 1) && (socket != null))
                log(" An incoming request is being assigned");

        }
  

接下來看看與處理器建立相關程式碼,因為一個聯結器中有可以有多個處理器,因此檢視各個處理器建立的過程是很有必要的,這裡的多個處理器採用的是處理器池是實現的,跟dbcp資料庫連線池的實現方式很相似,接下來看程式碼


6.httpConnector中createProcessor()方法
注,其中processors的宣告是這樣的:

private Stack<Object> processors = new Stack<Object>();
private HttpProcessor createProcessor() {

        synchronized (processors) {
            // 池中有處理器可用
            if (processors.size() > 0) {

                return ((HttpProcessor) processors.pop());
            }
            // 如果處理器池中沒有可以用的處理器,則判斷當前的處理器個數(此時池中是空的)是否大於設定最大處理器個數,

            if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
                // 沒有則建立
                return (newProcessor());
            } else {
                // 如果處理器最大個數被設定為-1,則要多少個處理器就建立多少個,不受限制
                if (maxProcessors < 0) {

                    return (newProcessor());

                } else {

                    return (null);
                }
            }
        }
    }
 

7.httpConnector中newProcessor()方法

private HttpProcessor newProcessor() {

        // 當建立一個處理器,則當前處理器標記加1,給改處理器設定了個名字,執行緒也是這麼做的
        HttpProcessor processor = new HttpProcessor(this, curProcessors++);
        if (processor instanceof Lifecycle) {
            try {
                // 在HttpProcessor類中的start方法裡啟動processor執行緒(沒建立一個處理器就馬上啟動,但是啟動萬以後並沒有讓processor的run方法馬上執行,而是出於wait狀態)
                ((Lifecycle) processor).start();
            } catch (Exception e) {
                log("newProcessor", e);
                return (null);
            }
        }
        created.addElement(processor);
        return (processor);

    }
 

接下來我們看看HttpProcessor中相關程式碼
1.HttpProcessor中start()方法

// 基本上都是用在start方法中啟動自己的執行緒的。
    public void start() // throws LifecycleException
    {

        // if (started)
        // throw new LifecycleException
        // (sm.getString("httpProcessor.alreadyStarted"));
        // lifecycle.fireLifecycleEvent(START_EVENT, null);
        // started = true;

        threadStart();

    }
 

2.HttpProcessor中start()方法

 private void threadStart() {

            //log(sm.getString("httpProcessor.starting"));

            thread = new Thread(this, threadName);
            //設定為守護執行緒,因為tomcat是為web應用程式服務的,所以他的執行緒一般都是守護執行緒
            //同時,在守護執行緒中建立的執行緒即使不setDaemon,也是守護執行緒
            thread.setDaemon(true);
            //開啟processor中的run方法。
            thread.start();

            if (debug >= 1)
                log(" Background thread has been started");

        }
 

3.HttpProcessor中run()方法

public void run() {

         // Process requests until we receive a shutdown signal
        while (!stopped) {

            //當前執行緒等待下一個socket來以後啟用所有的等等的執行緒(就是處理器建立以後不馬上執行完,而是出於wait狀態等待socket來以後並被別的執行緒啟用)
            Socket socket = await();
            if (socket == null)
                continue;

            // Process the request from this socket
            try {
            //該方法就是處理socket,使用者解析http頭,建立request和response物件(以後會單獨詳細講)
                process(socket);
            } catch (Throwable t) {
                log("process.invoke", t);
            }

            // Finish up this request
            connector.recycle(this);
 // Tell threadStop() we have shut ourselves down successfully
        synchronized (threadSync) {
            threadSync.notifyAll();
        }
        }

4.HttpProcessor中await()方法

 private synchronized Socket await() {

        // Wait for the Connector to provide a new Socket
        while (!available) {
            try {
            //就是呼叫當前物件的wait()方法
                wait();
            } catch (InterruptedException e) {
            }
        }
    }
 

5.HttpProcessor中process()方法

public void process(Socket socket)
{
//該方法是處理http頭和內容的,接下來會詳細講
}
 

到此,tomcat中聯結器的執行過程基本結束了,怎麼處理socket會在之後詳細講

 

相關文章