1. 程式人生 > >Jetty9原始碼剖析 - Connection元件 - HttpOutput

Jetty9原始碼剖析 - Connection元件 - HttpOutput

轉載自ph0ly:http://www.ph0ly.com

一、概念

HttpOutput實現了ServletOutputStream,提供應用層寫資料的各種操作

二、繼承體系

繼承體系

HttpOutput繼承自ServletOutput,實現了Runnable,和HttpInput基本一致,沒啥說的

三、原始碼剖析

1. 建立

建立

前面說過HttpOuput是在HttpChannel建立時建立,和HttpInput一樣,它仍然是一條連線一個例項,上圖是它的建構函式
比較簡單,用了個WriteBlocker,其實是一把帶超時的鎖

2. 寫資料

write

HttpOutput其實是支援非同步寫,裡面也帶了一個狀態機,不過這篇文章我們僅看同步模式下的寫
上圖是write方法的一部分,也是它最核心的地方
對於應用層呼叫write操作,如果應用寫入的資料量小於配置的提交大小,就會積攢buffer,等達到提交大小時,再呼叫write方法寫,或者使用者層寫入的資料直接就很大,超過了提交大小,就直接寫

接下來看下write方法的實現

write-2

可以看到利用Blocker這把阻塞鎖,呼叫write後阻塞,而write其實調了攔截器,前面提到攔截器就是HttpChannel

write-3

上圖是HttpChannel的write方法,也就是上面呼叫的攔截器方法,這裡就會調HttpChannel.sendResponse,而在HttpChannel章節提到過,sendResponse方法會呼叫HttpTransport類的send方法,即HttpConnection.send,最後HttpConnection會呼叫EndPoint往SocketChannel寫資料,這樣就完成了資料響應

3. 關閉

close

前面提到了write操作會積攢buffer,而HttpOutput也沒有什麼超時機制來保證刷資料,那是哪裡觸發刷的呢?其實HttpOutput提供了兩種方式,第一種是flush,應用層直接調OutputStream.flush,另一種是應用層完成資料寫入,並完成業務處理,這時控制權就回到Jetty框架層,而Jetty發現這個請求已經完成處理,這時候會在HttpChannel裡面觸發HttpOutput.close方法(當然不一定是直接觸發)
這裡我們看default分支,就會調write刷資料

4. 回收

recycle

由於HttpOutput是同一連線共享,因此每一個請求完成後都需要回收,可以看到就是把一些狀態或引數置為初始狀態

四、總結

HttpOutput最核心的也就是刷資料了,而在刷的策略上,它選了將小的Buffer積攢成一個大Buffer,實現更高效的資料寫入,如果面對較大Buffer,則直接刷出去,這種策略都是比較常見的。這篇文章就寫這麼多,對於非同步寫這篇文章沒提過多,後續將會和Servlet3非同步專題來更詳細說明。接下來的文章我會繼續分析下一個元件HttpGenerator,歡迎大家持續關注~