爲何要有 Servlet ,什麼是 Servlet 容器,什麼是 Web 容器?

本文已收錄至 https://github.com/yessimida/yes ,這裏有個人全部文章分類彙總,歡迎 star!java

如下代碼相信你們都很熟悉,大學時學 Java Web 都寫過這樣的代碼。git

從第一次接觸 Servlet 到以後的很長一段時間內,我都沒理解 Servlet 是個什麼玩意?github

爲何要有 Servlet ?web

爲何要有 Servlet 容器?面試

啥又是 Web 容器、HTTP 服務器?算法

今兒我們就來盤盤,而且從中來看看架構和框架的設計套路。瀏覽器

看完以後可能對接口、抽象會有進一步的認識。服務器

來,上車!微信

正文

首先瀏覽器發起 HTTP 請求,像早期的時候只會請求一些靜態資源,這時候須要一個服務器來處理 HTTP 請求,而且將相應的靜態資源返回。架構

這個服務器叫 HTTP 服務器。

簡單點說就是解析請求,而後得知須要服務器上面哪一個文件夾下哪一個名字的靜態文件,找到返回便可。

而隨着互聯網的發展,交互愈加得重要,單純的靜態文件知足不了需求。

業務變得複雜,須要咱們編寫代碼來處理諸多業務。

須要根據 HTTP 請求調用不一樣的業務邏輯來響應,可是咱們的業務代碼不能跟 HTTP 服務器耦合起來。

總不能在 HTTP 服務器的具體實現裏面來作判斷到底須要調用哪一個業務類吧?

這就把非業務和業務強相關了。

因此須要作一層抽象,將 HTTP 的解析和具體的業務隔離。

本質上的需求就是根據 HTTP 請求找到對應的業務實現類而後執行邏輯再返回。

業務千千萬,因此須要規定一個接口,因此業務類都實現這個接口這樣纔好對接。

這就是接口的含義,就像 USB。

這個接口就是 Servlet,固然這是最狹義的解釋。

Servlet 實際上是 Server Applet,全稱 Java Servlet,指的是用Java 編寫的服務端程序。

其實指代的是實現 Servlet 接口的那些業務類。

這就是 Servlet 的由來。

而 Servlet 容器其實就是管理和加載這些 Servlet 類的,拿到 HTTP 請求以後找到對應的 Servlet 類這就是 Servlet 容器要作的事情。

看到這是否是以爲還能再抽一層?由於這好像也和具體的業務實現不要緊?

是的,還能抽一層。

不必把 Servlet 容器作的事情和具體的業務耦合起來,業務反正照着 Servlet 接口實現就行,這樣 Servlet 容器就能夠加載它和管理它。

把請求和哪一個 Servlet 對應關係也抽象出來,就是 web.xml 了,我們在配置裏面告訴 Servlet 容器對應關係便可。

我圖中的業務實現其實對應的就是咱們日常的 war 包,這就是業務和 Servlet 容器的解耦。

想必你也聽過 Servlet 規範,其實 Servlet 接口和 Servlet 容器這一整套包括目錄命名啊啥的合起來就叫 Servlet 規範。

全部相關的中間件按照 Servlet 規範實現,咱們也按 Servlet 規範來實現業務代碼,這樣咱們就能在不一樣場景選擇不一樣的 Web 中間件。

反正規範的目的就是爲了對接方便,減小對接成本。

至此 HTTP 服務器、Servlet 、Servlet 容器想必都清晰了。

而 Web 容器其實就是 HTTP 服務器 + Servlet 容器,由於單單 Servlet 容器沒有解析 HTTP 請求、通訊等相關功能。

因此把 Tomcat、Jetty 等實現包含了 HTTP 服務器和 Servlet 容器的功能,稱之爲 Web 容器。

從咱們的分析一層一層的剝離,一層一層的抽象,相信你對 Web 有了更進一步的認識,我再畫個 Tomcat 的分析圖,應該就很清晰了。

從上面的一步步分析能夠看出:其實架構的設計就是一系列相關的抽象。

先是抽象出 HTTP 服務,用來通訊和解析協議。

再由於業務的複雜,爲了避免和 HTTP 服務耦合又抽象了一層 Servlet。

由 Servlet 加載和管理 Servlet ,來控制請求轉發到指定的 Servlet 實現類。

而後咱們安心的開發業務便可。

由於抽象因此靈活易擴展,好比如今是 HTTP1.1 服務,能夠換成 HTTP 2。

如今用 Tomcat 來做爲 Servlet 容器,也能夠換成 Jetty。

如今用原生的實現 Servlet 來作業務,也能夠換成 SpringMVC。

隨意變動,由於都抽象出來了,就很好替換,只要遵循約定的接口實現便可。

框架設計的一個套路

看完了架構設計的套路,再說說框架套路。

接口和抽象類。

全部中間件設計必用的套路,固然咱們本身的代碼也會這樣用。

定義一個接口來約定一些動做,能作啥作啥。

而後再定義一個抽象類來實現這個接口,用來實現一些通用的邏輯,作到代碼的複用。

而後再搞一些經常使用的實現類繼承抽象類,方便開發者的使用。

剩下的就留給開發者自行擴展便可。

而後抽象類都會使用模板方法,也就是定義執行的流程,具體實現邏輯由子類自行實現。

這就是必用的套路。

接口約束、抽象類代碼複用、實現經常使用實現類方便使用、剩下的自行擴展。

拿 Servlet 舉例,首先定義 Servlet 接口。

public interface Servlet {
    void init(ServletConfig config) throws ServletException;
    ServletConfig getServletConfig();
    void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
    String getServletInfo();
    void destroy();
}

而後搞了個通用抽象類 GenericServlet,不過這個抽象類邏輯比較簡單。

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
  ................省略一些.............
   @Override
    public ServletConfig getServletConfig() {
        return config;
    }
    @Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
................省略一些.....................
}

而後搞了個經常使用的 HttpServlet 繼承了 GenericServlet。

public abstract class HttpServlet extends GenericServlet {

    private static final long serialVersionUID = 1L;

    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
  ....................
}

套路就是這麼個套路,以後面試官問你接口和抽象類的問題,相信你也能答出來了。

最後

套路你們應該都 GET 到了。

想必你們都聽過「計算機科學中的每一個問題均可以用一間接層解決」。

是的,基本上全部問題抽象一層都能解決。

若是一層不夠,那就兩層。

歡迎加我好友進行深刻地交流,備註「進羣」,拉你進交流&內推羣。

平日的面試題遇到難處,或者看某個知識點翻遍全網的資料仍是感受很模糊、不透徹,能夠私聊我,給我留言。

遇到合適的我會整理寫出一篇文章,我不會的去請教別人也給整出來。

那種工做遇到很細節的場景的仍是別了,這種問你上司比較合適:)

歡迎關注個人公衆號【yes的練級攻略】,更多硬核文章等你來讀。

巨人的肩膀

《深刻拆解Tomcat & Jetty》 李號雙


微信搜索【yes的練級攻略】,關注 yes,回覆【123】一份20W字的算法刷題筆記等你來領,從一點點到億點點,咱們下篇見。
我的文章彙總:https://github.com/yessimida/yes 歡迎 star !

相關文章
相關標籤/搜索