我們回顧一下,第一章實現的Web服務器類圖大致如下:
其中HttpServer
中的await()
方法會使用一個ServerSocket
來監聽8080
端口,用來接收客戶端的請求。當接收到用戶請求後會創建一個Socket
對象,通過與Socket
關聯的InputStream
來創建並填充一個Request
對象(這裡只是簡單的填充了Uri)。然後用Socket
關聯的OutputStream
創建一個Response
對象,並持有一個Request
對象。最後通過調用Response
對象中的sendStaticResource()
方法來向客戶端發送靜態頁面(其中根據request.getUri()
來決定返回哪個頁面)。
而第二章實現的Web服務器有什麼改進的地方?
首先摒棄了第一章中自定義的Response
和Request
類,而是根據Servlet
標准提供的接口來定義類。Servlet
編程是通過 javax.servlet
和 javax.servlet.http
這兩個包的類和接口來實現的。其中一個至關重要的就是javax.servlet.Servlet
接口了。所有的 servlet
必須實現實現或者繼承實現該接口的類。Servlet
接口有五個方法:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;">
public interface Servlet {
public void init(ServletConfig config) throws ServletException;
public ServletConfig getServletConfig();
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
public String getServletInfo();
public void destroy();
}
其中init
、service
和destory
是Servlet
的生命周期方法。init
只會在Servlet
實例化完成後被調用一次,service
會在每次請求該Servlet
時被調用,而destory
會在該Servlet
卸載時被調用,這通常發生在Servlet
容器正在被關閉或者Servlet
容器需要一些空閒內存的時候。
在第二章中實現的Web服務器將會以Servlet
容器的角度來編程。總的來說,一個全功能的Servlet
容器會為servlet
的每個HTTP請求做下面一些工作:
Servlet
的時候,加載該Servlet
類並調用Servlet
的init
方法(僅一次) 對每次請求,構造一個javax.servlet.ServletRequest
實例和一個javax.servlet.ServletResponse
實例 調用servlet
的service
方法,並傳入ServletRequest
和ServletReponse
實例 當servlet
容器被關閉時,調用servlet
的destory
方法並卸載servlet
類
那麼如何加載Servlet類呢,我們可以用
Class.forName(xxx)
來加載一個類。也可以用java.net.URLClassLoader
類,它是java.lang.ClassLoader
類的一個直接子類。擁有一個URLClassLoader
實例,那麼就可以直接使用它的loadClass
方法去加載Servlet
類了。這裡我們就直接用URLClassLoader
最簡單的構造函數:URLClassLoader(URL[] urls)
,這裡的URL
數組就指定了類所在的目錄位置(通常叫repository
)。不過由於雙親加載機制,如果在classpath
下已經存在某個類,就加載不到repository
中的對應類了。
剛才說了這裡會摒棄第一章的Request
和Response
類。而新的Request
和Response
類分別實現了 javax.servlet.ServletRequest
接口和javax.servlet.ServletResponse
接口,只不過在目前很多方法都留空了。第二章的類圖大致如下:
HttpServer
依舊監聽8080
端口等待客戶端連接,根據請求內容創建並填充Request
對象,並創建Response
對象。Request
和Response
類中的大多數方法都是留空的。然後會根據請求內容來判斷是創建ServletProcessor
實例還是創建StaticResourceProcessor
實例,對了,這裡的話我個人覺得在兩個Processor
之上再創建一個Processor
接口並讓它們實現這個接口更加好一些。如果是StaticResourceProcessor
,那麼直接返回請求的靜態內容。而如果是ServletProcessor
,那麼則去加載請求的Servlet
類,然後調用Servlet
的doService
方法來進行處理並響應給客戶端。