Servlet概述
為什麼要學習Servlet
Java Web的演變過程大概可以分為4個階段:
- Servlet + jdbc + jsp
- Spring + Struts2+ Hibernate(SSH)
- Spring + SpringMVC + Mybatis(SSM)
- 微服務階段
前兩個階段基本上可以說是歷史了,當今Spring家族一統天下。
現在實際開發中很少直接使用Servlet了,但是各個框架的底層還是大量使用了Servlet,學習Servlet對後續各個框架的理解和學習都很有幫助。
什麼是 Servlet
Servlet 是執行在 Web 伺服器或應用伺服器上的程式,它是作為來自 Web 瀏覽器或其他 HTTP 客戶端的請求和 HTTP 伺服器上的資料庫或應用程式之間的中間層。
Servlet其實就是一個遵循Servlet開發的java類。Serlvet是由伺服器呼叫的,執行在伺服器端。
Servlet帶給我們最大的作用就是能夠處理瀏覽器帶來HTTP請求,並返回一個響應給瀏覽器,從而實現瀏覽器和伺服器的互動。
工作流程
-
Tomcat將瀏覽器提交的請求封裝成HttpServletRequest物件,同時將輸出流封裝成HttpServletResponse物件
-
Tomcat把request、response作為引數,呼叫Servlet的相應方法,例如doGet(request, response)等
-
Servlet中主要處理業務邏輯
生命週期
在 Web 容器中,Servlet 主要經歷 4 個階段,如下圖:
- 載入Servlet。當Tomcat第一次訪問Servlet的時候,Tomcat會負責建立Servlet的例項
- 初始化。當Servlet被例項化後,Tomcat會呼叫
init()
方法初始化這個物件 - 處理服務。當瀏覽器訪問Servlet的時候,Servlet 會呼叫
service()
方法處理請求 - 銷燬。當Tomcat關閉時或者檢測到Servlet要從Tomcat刪除的時候會自動呼叫
destroy()
方法,讓該例項釋放掉所佔的資源。一個Servlet如果長時間不被使用的話,也會被Tomcat自動銷燬 - 解除安裝。當Servlet呼叫完
destroy()
方法後,等待垃圾回收。
如果有需要再次使用這個Servlet,會重新呼叫init()
方法進行初始化操作。
只要訪問Servlet,service()
就會被呼叫。init()
只有第一次訪問Servlet的時候才會被呼叫。
destroy()
只有在Tomcat關閉的時候才會被呼叫。
處理請求的方法
Servlet 即實現了 Servlet 介面 的類,實現 Servlet 介面 的時候,需要實現5個方法
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
為了方便使用可以直接繼承 HttpServlet 類,該類已經預設實現了 Servlet 介面中的所有方法。
在編寫 Servlet 的時候,只需要重寫你需要的方法就好了。
並且該類還在原有 Servlet 介面上新增了一些與 HTTP 協議處理相關的方法。
- Servlet 處理請求的方法一共有三種:
- 實現
service()
方法 - 重寫
doGet()
- 重寫
doPost()
- 實現
HttpServletRequest 和 HttpServletResponse
對於每次訪問請求,Servlet引擎都會建立一個新的HttpServletRequest請求物件和一個新的HttpServletResponse響應物件,即 request 和 response 物件。
HttpServletRequest 常用方法
String getContextPath()
獲取上下文路徑String getHeader(String headName)
根據指定的請求頭獲取對應的請求頭的值.String getRequestURI()
返回當期請求的資源名稱. 上下文路徑/資源名StringBuffer getRequestURL()
返回瀏覽器位址列的內容String getRemoteAddr()
返回請求伺服器的客戶端的IP
獲取請求引數的方法:
String getParameter(String name)
根據引數名稱,獲取對應引數的值.String[] getParameterValues(String name)
根據引數名稱,獲取該引數的多個值.Enumeration getParameterNames()
獲取所有請求引數的名字Map<String,String[]> getParameterMap()
返回請求引數組成的Map集合.
HttpServletResponse 常用方法
-
OutputStream getOutputStream():
獲取位元組輸出流:檔案下載 -
Writer getWriter()
獲取字元輸出流:輸出內容 -
resp.setContentType("text/html;charset=utf-8")
設定檔案輸出的編碼格式和內容型別
-
resp.sendRedirect()
302重定向,臨時跳轉
301要使用另外的手段
Servlet 是單例的
解釋
瀏覽器多次對Servlet的請求,一般情況下,伺服器只建立一個Servlet物件,也就是說,Servlet物件一旦建立了,就會駐留在記憶體中,為後續的請求做服務,直到伺服器關閉。
每次訪問請求物件和響應物件都是新的
對於每次訪問請求,Servlet引擎都會建立一個新的HttpServletRequest請求物件和一個新的HttpServletResponse響應物件,然後將這兩個物件作為引數傳遞給它呼叫的Servlet的service()
方法,service()
方法再根據請求方式分別呼叫其他方法。
執行緒安全問題
當多個使用者訪問Servlet的時候,伺服器會為每個使用者建立一個執行緒。當多個使用者併發訪問Servlet共享資源的時候就會出現執行緒安全問題。
原則
- 如果一個變數需要多個使用者共享,則應當在訪問該變數的時候,需要加鎖
- 如果一個變數不需要共享,則直接在 doGet() 或者 doPost()定義,這樣不會存線上程安全問題
通過註解配置 Servlet
在之前的開發工作中,每次編寫一個Servlet都需要在web.xml檔案中進行配置
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>com.web.controller.ActionServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>/servlet/ActionServlet</url-pattern>
</servlet-mapping>
而當一個專案中存在很多 Servlet,那麼配置檔案就會變得很亂很大,在 Servlet 3.0 推出之後,我們可以使用註解來配置 Servlet
@WebServlet(name = "ActionServlet", urlPatterns = "/servlet/ActionServlet")
Web 元件之間的跳轉方式
請求轉發(forward)
又叫做直接轉發方式,客戶端和瀏覽器只發出一次請求,Servlet、HTML、JSP或其它資訊資源,由第二個資訊資源響應該請求,在請求物件request中,儲存的物件對於每個資訊資源是共享的。
比如:從 AServlet 請求轉發到 BServlet
- 語法:
request.getRequestDispatcher(path).forward(request, response);
引數:path
,要跳轉到的資源路徑:上下文路徑 / 資源路徑
- 特點:
- 位址列中的地址不變
- 只有一個請求
- 資源是共享的
- 可以訪問 WEB-INF 中的資源
- 請求轉發不能跨域訪問
URl 重定向(redirect)
又叫做間接轉發方式(Redirect)實際是兩次HTTP請求,伺服器端在響應第一次請求的時候,讓瀏覽器再向另外一個URL發出請求,從而達到轉發的目的。
比如:從AServlet重定向到BServlet
- 語法:
response.sendRedirect(String location);
引數:location
,轉發到的資源路徑
- 特點:
- 位址列中的地址【會】發生改變
- 有兩個請求
- 在兩個 Servlet 中不可以共享請求中的資料
- 最終的響應由BServlet來決定,和 AServlet 沒有關係
- 不可以訪問 WEB-INF 中的資源
- 請求轉發可以跨域訪問