tomcat源碼分析學習筆記(三)

——每天的寥寥幾筆,堅持下去,將會是一份沉甸甸 的積累。


今天的筆記是針對《tomcat how works》第四章——tomcat的默認連接器來講的。


1.在上一篇文章我羅列書第三章的源碼目錄,如下:

connector:      RequestStream,ResponseStream,ResponseWriter

connnectot.http:HttpConnector,HttpProcessor//前者用於創建serverSocket,監聽客戶端請求;後者是個關鍵類,後面單獨講

		HttpRequest,HttpResponse,HttpRequestFacade,HttpResponseFacade
			    //request和response實現了HttpRequestServlet和HttpResponseServlet接口,相關填充數據由下面兩個對象提供

		HttpHeader,HttpRequestLine//HTTP消息的頭部,請求行封裝出的兩個實體類

		SocketInputStream//用Socket.InputStream封裝出的新的類,實現了讀取HTTP消息的頭部和請求行,封裝到上面兩個對象中

		Constants//存一些常量,降低耦合度,便於修改

core:           servletProcessor,staticResourceProcessor
			//這兩個類爲業務處理類,就servlet而言,會根據connector解析出的處理類類名,用反射機制實例化某servlet類來處理。


其實每章就是在之前簡單的基礎上進行擴張充實。在第四章裏,覆蓋了我們自己寫的HttpConnector,HttpProcessor,採用了org.apache.catalina.connector.http.HttpConnector和org.apache.catalina.connector.http.HttpProcessor(實現了多處理器線程,可以用來處理不同的客戶端請求);並新增了一個處理servlet的容器SimpleContainer。【源碼及書籍下載鏈接:http://pan.baidu.com/s/1ntBhXX3


2.再強調一下,第四章的突破點在於:“多處理線程”,所以需要多線程的相關知識,不是很熟的,建議先給自己充下電。馬上,下一篇我也會提供相關筆記的。


3.接下來把處理請求的執行流程給梳理下。

(1)bootstrap類啓動

    HttpConnector connector = new HttpConnector();
    SimpleContainer container = new SimpleContainer();
    connector.setContainer(container);
    try {
      connector.initialize();
      connector.start();
解釋:
- 創建一個Httpconnector連接器,set一個container容器(這個後面解釋);
- 初始化操作:會調用open()函數,而open()函數會調用DefaultServerFactory來生產serverSocket對象(前三章都是直接new出來的,這裏用到了工廠)
- start操作:會new出來5個(默認,等於minProcessors)httpProcessor對象(通過調用newProcessor()函數,這個函數會啓動httpProcessor自身的線程,即run函數已經跑起來),然後添加到棧中(源碼如下)。
    start():
        while (curProcessors < minProcessors) {
            if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
                break;
            HttpProcessor processor = newProcessor();
            recycle(processor);//加入棧中
        }
    newProcessor():
	private HttpProcessor newProcessor() {
        //        if (debug >= 2)
        //            log("newProcessor: Creating new processor");
        HttpProcessor processor = new HttpProcessor(this, curProcessors++);
        if (processor instanceof Lifecycle) {
            try {
                ((Lifecycle) processor).start();//httpProcessor實現了runnable接口,調用start函數直接啓動線程,具體源碼後面提到
            } catch (LifecycleException e) {
                log("newProcessor", e);
                return (null);
            }
        }
        created.addElement(processor);
        return (processor);
}

(2)其實(1)中的connector.start()還會進行一個操作,就是啓動httpConnector線程(這個類也實現了runnable接口)。於是自然而然,start函數一執行,便進入run函數

//極簡模式   
 public void run() {
        while (!stopped) {
		//監聽客戶端請求
		//獲取socket對象
            processor.assign(socket);//將Socket對象傳到httpProcessor裏面處理
        }
    }


(3)httpProcessor類。主要功能依舊是封裝request,response對象的相關數據,用於觸發相關servlet的service方法。封裝數據的過程,也就涉及http消息解析,前一篇文章講到了parseRequest,parseHeaders等,在本文中該類將繼續拓展,新增瞭如parseAcceptLanguage等。

除了上面提到的幾個咱們熟悉的方法之外,又新增了assign()和await()方法,下面詳細介紹(設計的非常巧妙),主要看看代碼裏我的文字介紹

public void run() {
        while (!stopped) {
            Socket socket = await();
//流程從這開始:
//new出這個processor對象的時候已經觸發run方法(上面講過),然後調用await()方法,由於默認available=false,
//因此await方法調用wait()方法,是的線程進入等待狀態(等待notify方法喚醒)
//知道httpConnector調用assign方法,是的available=true,然後又notify,使得線程被喚醒,正好available=true,跳出while循環,
//available又被賦成false。此時run中的socket不爲null,調用process方法進行處理,最後將封裝好的request和response對象作爲參數觸發serlvet容器的處理程序
            if (socket == null)continue;
            try {
                process(socket);
            } catch (Throwable t) {}
            connector.recycle(this);
        }
    }

private void process(Socket socket) {//極簡,刪掉了細節部分
        connector.getContainer().invoke(request, response);
    }

synchronized void assign(Socket socket) {
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        this.socket = socket;
        available = true;
        notifyAll();
    }
private synchronized Socket await() {
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        Socket socket = this.socket;
        available = false;
        notifyAll();
        return (socket);
    }


(4)還有一個SimpleContainer類,這個就是servlet容器,用來接收request,response對象,解析request得到相應的servlet,根據反射機制,觸發改serlvet的service方法

 

public void invoke(Request request, Response response)throws IOException, ServletException {
      servlet.service((HttpServletRequest) request, (HttpServletResponse) response);//主要就是這個invoke方法,和上的process方法掛鉤
    }


由於涉及到多線程相關知識,理解起來可能有些難度。下一篇我會整理一份多線程相關的筆記以供大家參考。

又週一了,可能接下來幾天更新頻率不會那麼高(學生黨要上課),不過依舊會盡量保持進度(各種學長阿里,騰訊的offer紛紛到手,學弟甚是欣羨,必須加倍努力)。。。。




發佈了52 篇原創文章 · 獲贊 9 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章