初學JavaWeb開發,請遠離各類框架,從Servlet開始。html
Web框架是開發者在使用某種語言編寫Web應用服務端是關於架構的最佳實踐。不少Web框架是從實際的Web項目抽取出來的,僅和Web的請求和響應處理有關,造成一個基礎,在開發別的應用項目的時候則能夠從這個剝離出來的基礎作起,讓開發者更關注具體的業務問題,而不是Web的請求和響應的控制。
框架不少,但套路基本相似,幫你隱藏不少關於HTTP協議細節內容,專一功能開發。
但對於一個初學者來講,過早的接觸框架每每事倍功半!一樣一個問題,換一種框架你可能須要從頭開始研究。
因此,做爲Java Web技術的核心基礎,Servlet的工做原理是必須掌握的,也是成爲一名合格的Java Web技術開發人員的基本要求。
1、Servlet簡介
Servlet是Server與Applet的縮寫,是服務端小程序的意思。是SUN公司提供的一門用於開發動態Web資源的技術。目前最新版本爲3.1。
Servlet本質上也是Java類,但要遵循Servlet規範進行編寫,沒有main()方法,它的建立、使用、銷燬都由Servlet容器進行管理(如Tomcat)。
Servlet是和HTTP協議是緊密聯繫的,其能夠處理HTTP協議相關的全部內容。這也是Servlet應用普遍的緣由之一。
提供了Servlet功能的服務器,叫作Servlet容器,其常見容器有不少,如Tomcat, Jetty, resin, Oracle Application server, WebLogic Server, Glassfish, Websphere, JBoss等。
2、Servlet工做原理解析
一、一個HTTP請求的執行過程:
客戶端發出請求
http://localhost:8080/xxx
根據Web.xml文件的配置,找到<url-pattern>對應的<servlet-mapping>
讀取<servlet-mapping>中<servlet-name>的值
找到<servlet-name>對應的<servlet-class>
找到該class並加載執行該class
二、Servlet的執行過程
Servlet程序有Web服務器調用,當收到請求後,
檢查是否已裝載並建立了該Servlet對象,若是沒有則加載建立
調用Servlet的init()方法初始化實例
調用service()方法,處理請求並返回響應結果
在服務器被中止或重啓以前,調用destroy()方法釋放資源
三、Servlet接口實現類
SUN公司定義了兩個實現類,GenerricServlet和HttpServlet,其中後者是前者的子類,它在原有基礎上添加了一些HTTP協議處理方法,它比GenerricServlet功能更強大,因此咱們通常將本身的類繼承自HttpServlet,並重寫doGet方法和doPost方法,不須要重寫Service方法。
四、Servlet的一些細節
4.一、因爲客戶端是經過URL地址訪問web服務器中的資源,因此Servlet程序弱項被外界訪問,必須把Servlet程序映射到一個URL地址上,這個工做在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成(在Servlet3.0規範的新特性中,該功能可使用註解完成,不要求必須使用web.xml,只用註解更簡單,該特性會在後文進行詳細講解)。
<servlet>元素用於註冊Servlet,它包含兩個主要的子元素:<servlet-name>和<servlet-class>,分別用於設置Servlet的註冊名稱和Servlet的完整類名。
<servlet-mapping>元素用於映射一個已註冊的Servlet的一個對外訪問路徑,它包含兩個子元素:<servlet-name>和<url-pattern>,分別用於指定Servlet的註冊名稱和Servlet的對外訪問路徑。
-
<web-app> <servlet> <servlet-name>AnyName</servlet-name><!--自定義的邏輯名--> <servlet-class>HelloServlet</servlet-class><!--Servlet對應類的全類名--> </servlet> <servlet-mapping> <servlet-name>AnyName</servlet-name><!--上面定義的邏輯名--> <url-pattern>/demo/hello.html</url-pattern><!--匹配的URL--> </servlet-mapping> </web-app>
4.二、同一個Servlet能夠被映射到多個URL上,即多個<servlet-mapping>元素的<servlet-name>子元素的設置值能夠是同一個Servlet的註冊名。java
在Servlet映射到的URL中也可使用*通配符,可是隻能有兩種固定的格式:
一種是「*.擴展名」。
另外一種是以(/)開頭並以(/*)結尾。
-
<!--方式一用於匹配全部某一擴展名的文件--> <servlet-mapping> <servlet-name>AnyName</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!--方式二用於匹配某一文件夾下的全部文件--> <servlet-mapping> <servlet-name>AnyName</servlet-name> <url-pattern>/action/*</url-pattern> </servlet-mapping>
兩個特色:能夠精確匹配,就用精確匹配,最後使用範圍最寬泛的匹配web
/* 的優先級高於 *.擴展名 會先匹配
4.三、若是某個Servlet的映射路徑只有一個(/),那麼這個Servlet就成爲當前Web應用程序的缺省Servlet。
凡是在web.xml文件中找不到匹配的<servlet-mapping>元素的URL,它們的請求訪問都將交給缺省Servlet處理,也就是說,缺省Servlet用於處理全部其餘Servlet都不處理的訪問請求。
在tomcat的安裝目錄/conf/web.xml中,註冊了一個名稱org.apache.catalina.servlets.DefaultServlet的Servlet,並將這個Servlet設置爲缺省Servlet。
當訪問Tomcat服務器中的某個靜態HTML文件或圖片等資源時,其實是在訪問這個缺省Servlet。
五、Servlet的生命週期
Servlet沒有main()方法,不能獨立運行,它的運行徹底由Servlet引擎來控制和調度。
針對客戶端的屢次Servlet請求,一般狀況下,服務器只會在第一次請求的時候建立一個Servlet實例對象,並駐留在內存中,爲後續的其餘請求服務,直至web容器退出,Servlet實例對象纔會銷燬。
在Servlet的整個生命週期內,Servlet的init()方法只被調用一次,而對於每個請求都會調用一次Servlet的service()方法service根據請求方式調用doGet或doPost方法
若是在<servlet>元素中配置了一個<load-on-startup>元素,那麼WEB應用程序在啓動時,就會裝載並建立實例對象、以及調用Servlet實例對象的init()方法。能夠在啓動的時候爲整個WEB應用建立一些必要的的資源或鏈接。但若是全部的Servlet都啓動加載,則會大大增長服務器負擔,並且有些Servlet永遠也不會被客戶訪問到,白白浪費資源,因此從性能角度,應合理利用該特性。
<servlet> <servlet-name>invoker</servlet-name> <servlet-class> org.apache.catalina.servlets.InvokerServlet </servlet-class> <load-on-startup>2</load-on-startup><!--數字表示啓動加載的優先級,大於0--> </servlet>
六、ServletConfig對象apache
在Servlet的配置文件中,可使用一個或對個<init-param>標籤爲Servlet配置一些初始化參數。
當Servlet配置了初始化參數後,web容器在建立Servlet實例對象時,會自動將這些初始化參數封裝到ServletConfig對象中,並在調用Servlet的init方法時,將ServletConfig對象傳似給Servlet,開發者能夠經過ServletConfig對象獲得初始化參數信息。
七、ServletContext對象
WEB容器在啓動時,它會爲每一個WEB應用程序都建立一個對應的Servlet對象,它表明當前web應用。
ServletConfig對象中維護了ServletContext對象的引用,開發者在編寫Servlet是,能夠經過ServletConfig.getServletContext方法得到該對象。
因爲一個WEB應用中的全部Servlet共享同一個ServletContext對象,所以Servlet對象之間能夠經過ServletContext對象來實現通信。ServletContext對象一般也被稱之爲Context域對象。
多個Servlet經過ServletContext對象實現數據共享。要確保注意線程安全。
能夠經過ServletContext對象獲取WEB應用的初始化參數。
能夠實現Servlet的轉發。getRequestDispatcher()方法
八、Servlet經常使用容器Tomcat(左圖:Tomcat容器;右圖:Servlet的執行流程)
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
九、
Servlet體系結構
![](http://static.javashuo.com/static/loading.gif)
從上圖能夠看出Servlet規範是基於這幾個類運轉的,與Servlet主動關聯的是三個類:ServletConfig、ServletRequest、ServletResponse。這三個類都是經過容器傳遞給Servlet的。
ServletConfig接口中的方法都是爲了獲取這個Servlet的一些配置屬性,而這些配置屬性可能在Servlet運行時被用到。
ServletContext就是這些配置屬性的上下文環境。
3、Servlet中的Session與Cookie
Servlet可以給咱們提供兩部分數據,一個是在Servlet初始化時調用init方法設置的ServletConfig,它基本包含了Servlet自己和Servlet所運行的Servlet容器中的基本信息。另外一個是ServletRequest提供的此次請求的HTTP協議信息,這部分須要很清楚HTTP協議。
Session與Cookie的做用都是爲了保持訪問用戶與後端服務器的交互狀態,各有優缺點。然而具備諷刺意味的是它們優勢和它們的使用場景又是矛盾的,例如使用 Cookie 來傳遞信息時,隨着 Cookie 個數的增多和訪問量的增長,它佔用的網絡帶寬也很大,試想假如 Cookie 佔用 200 個字節,若是一天的 PV 有幾億的時候,它要佔用多少帶寬。因此大訪問量的時候但願用 Session,可是 Session 的致命弱點是不容易在多臺服務器之間共享,因此這也限制了 Session 的使用。
Session正常工做的實現方式:小程序
基於URL Path Parameter,默認支持
基於Cookie,若不修改Context中的cookie標識,默認支持
基於SSL,默認不支持,只有connector.getAttribute("SSLEnabled")爲true時才支持。
4、Servlet中的Listener
整個Tomcat服務器中Listener使用的很是普遍,它是基於觀察者模式的,Listener的設計對開發Servlet應用程序提供了一種快捷的手段,可以方便的從另外一個縱向惟獨控制程序和數據,目前Servlet中提供了5中兩類事件的觀察者接口,他們分別是:4個EventListener類型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 個 LifecycleListeners 類型的,ServletContextListener、HttpSessionListener。
它們基本上涵蓋了整個Servlet生命週期中,你感興趣的每種事件,這些Listener的實現類能夠配置在web.xml中的<listener>標籤中,固然也能夠在應用程序中動態添加Listener,可是ServletContextListener在容器啓動以後就不能再添加新的,由於它監聽的事件已經不會再出現。掌握這些Listener的使用,可以讓咱們的程序設計的更加靈活。
5、Servlet3.0新特性註解
前面介紹過Servlet3.0提供了註解(annotation),使得再也不須要在web.xml文件中進行Servlet的部署描述。
開發者可使用@WebServlet註解將一個繼承於javax.servlet.http.HttpServlet的類標註爲能夠處理用戶請求的Servlet。
@WebServlet註解的相關屬性 NO. 屬性名 描述 1 asyncSupported 聲明Servlet是否支持異步操做模式 2 description Servlet的描述信息 3 displayName Servlet的顯示名稱 3 initParams Servlet的初始化參數 5 name Servlet的名稱 6 urlPatterns Servlet的訪問URL 7 value Servlet的訪問URL
Servlet的訪問URL是Servlet的必選屬性,能夠選擇使用urlPatterns或者value定義。後端
更多關於Servlet3.0的註解使用知識請參考博客: