1. 程式人生 > >Servlet必會必知

Servlet必會必知

Writer      :李強強(泥沙磚瓦漿木匠)

“眨眼間,離上一篇寫技術博文時隔1個月。怕自己真的生疏了,都是備案太慢惹得。哈哈,繼續high~ ”

[JavaEE 要懂的小事] Http相關 ,一直想寫點Web開發相關的。最近專案介面開發緊,還有準備新的九月份戰鬥。JDK IO原始碼就隔一段落,溫故知新看看Servlet & JSP 相關。把自己基礎累積回顧一遍,並和大家分享分享一些心得和程式碼。這裡應該涉及到一部分原始碼,開發思想和一些手工做出的圖。喜歡java,或者有一定Java開發經驗的多提寶貴意見。

一、Web伺服器

從事web開發的人,會很清楚一個東西叫HTTP伺服器

,比如JEE開發—TomcatJetty,.NET開發—ISS等。HTTP伺服器是使用 HTTP(超文字傳輸協議) 與客戶機瀏覽器進行資訊交流。下面就是HTTP伺服器簡單互動圖:(來自[JavaEE 要懂的小事] Http相關 部落格)

1_thumb3

HTTP伺服器Web伺服器的一種,也是開發最常見的,自然還有其他方式進行資訊互動,比如FTP檔案伺服器

Web伺服器是可以向發出請求的瀏覽器提供文件的程式。其核心過程為

連線過程 — 請求過程 — 應答過程 — 關閉連線

這讓我想到了Tomcat架構的一張圖:

image001

二、Tomcat 簡單說幾句

如圖,Tomcat 包含了核心服務模組:Connector連線模組 和 Container

容器。Tomcat Server 核心是一個 Servlet/JSP Container。對每一個HTTP請求,過程如下

獲取連線

Servlet來分析請求HttpServletRequest

— 呼叫其service方法,進行業務處理

— 產生相應的響應HttpServletResponse

關閉連線

如圖:

Tomcat相關

藍色線指向過程是請求,綠色線指向過程是響應過程。也就是上面Web伺服器核心過程:“連線過程 — 請求過程 — 應答過程 — 關閉連線

三、我第一個Servlet

什麼是Servlet?(每次都會不停的問自己,這是什麼“What”?緊接著應該是什麼用“How”吧)

Servlet 是執行在Web伺服器的Java小程式。Servlet可以獲取並針對Web客戶端的請求作出響應。一般情況下,通過HTTP,即超文字傳輸協議,進行傳輸通訊。”

A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol.

所以,Servlet 是Web伺服器核心工作的抽象。它不單單只是實現HttpServlet,可能實現有FtpServlet(這個我猜的)等。相對較多的Web開發,知道的肯定是HttpServlet。

JavaEE 6文件中,是這樣介紹HttpServlet

“HttpServlet 提供了一個能被繼承後建立一個適應Web網站的Http Servlet的抽象類。”

Provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site.

光說不練假把式,練一個“Hello,Servlet/JSP World!”:

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/*
 * Copyright [2015] [Jeff Lee]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @author Jeff Lee
 * @since 2015-6-25 19:46:45
 * 	HelloWrold案例
 */
@WebServlet(urlPatterns = "/helloWorld.html")
public class HelloWorldServletT extends HttpServlet{
	
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException{
		// 獲取輸出列印物件
		PrintWriter out = resp.getWriter();
		out.println("Hello,Servlet/JSP World!");
	}
}

右鍵該HelloWorldServletT.java檔案 — Run As — Run On Server — 選擇Tomcat伺服器 — Finish即可

image

image

等待片刻,你可看到網頁上如下輸出。這就是客戶端從HttpServlet獲取到的響應:

image

三、分析原始碼

@WebServlet(urlPatterns = "/helloWorld.html")

@WebServlet 註解用於宣告一個HttpServlet的配置。其中,urlPatters = “/helloWorld.html”,urlPatterns複數形式,說明至少一個URL必須被申明。它和另一個value必須存在一個,但不能同時存在。如果要匹配多個URL路徑的話,如下:

@WebServlet(urlPatterns = { "/helloWorld01.html", "/helloWorld02.html" }

下面有個@Override,重寫了父類HttpServletdoGet方法。我們先看看父類HttpServlet。HttpServlet是一個抽象類,它提供了以下方法:

— doGet  , 服務於 HTPP GET 請求

— doPost , 服務於 HTTP POST 請求

— doPut  , 服務於 HTTP PUT 請求

— doDelete,服務於 HTTP DELETE 請求

如圖:

image

對於不同請求,HttpServlet的子類必須相應的實現至少一個方法,通常來說,會是其中一個,這樣程式碼比較清晰。那父類的doGet方法做了什麼工作呢?

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

這裡就簡單的獲取了下HTTP協議及Http Local資訊,然後可以協議是否是1.1,做出分別是405或者400HTTP狀態碼的響應。

回到HelloWorldServletT.java 這裡:

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
		throws ServletException, IOException {
	// 獲取輸出列印物件
	PrintWriter out = resp.getWriter();
	out.println("Hello,Servlet/JSP World!");
}

表示該HelloWorldServletT會接受Http GET請求,並OOM到HttpServletRequest,並執行裡面的邏輯程式碼和返回響應。 這裡從HttpServletResponse物件中獲取到輸出列印物件PrintWriter,然後輸出了“Hello,Servlet/JSP World!”。

完畢!哦還有一點補充補充補充:

print,這裡還好一句話。如果列印個table會很麻煩,因此有一個JSP的東西出現了,是Servlet的HTML化身。

五、深入Servlet 具體過程

又回到這個簡單的 Get Servlet程式碼:

public class HelloWorldServletT extends HttpServlet{
	
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException{
		// 獲取輸出列印物件
		PrintWriter out = resp.getWriter();
		out.println("Hello,Servlet/JSP World!");
	}
}

這過程總結如下:

— 從瀏覽器(Client)獲取連線”/helloWorld.html”

Tomcat Connector模組將請求(Request)傳遞給 Container模組

Container 模組會做以下事情

—— 分析HTPP請求資訊,組裝成HttpServletRequest物件

—— 建立新的HttpServletResponse物件

—— 根據路由配置,搜尋相應的Servlet,並建立一個執行緒用於處理本次請求。此時執行緒會將上面RequestResponse物件的索引傳遞給Servlet

— 新執行緒中的Servlet處理邏輯

執行緒結束後,通過HttpServletResponse物件的PrintWriter,返回瀏覽器一個資訊

過程圖如下:

Tomcat相關

藍色線指向過程是請求,綠色線指向過程是響應過程,橙色線指向過程是內部處理過程。

有些面試題會這樣問:

Servlet是執行緒安全的嗎?

不是,一個servlet實現類只會有一個例項物件,多個執行緒是可能會訪問同一個servlet例項物件的,執行緒安全問題都是由全域性變數靜態變數引起的。

因此,Servlet物件例項化是在以第一次請求此Servlet時,如果訪問後,例項物件存在記憶體中,只會在伺服器停止時,它才會消失。它不會隨著各個執行緒結束而結束。因此下次訪問Servlet時,Servlet Container會搜尋相應的Servlet,如果不存在Container新建相應的Servlet。這也是我們想要的結果。

六、小結

發現這一部落格寫的太多,回頭一看。可以寫成三個文章了。言歸正傳本文要點如下

1、簡單介紹Web伺服器 及 Tomcat容器

2、第一個Sevlet的開發及使用

3、深入原始碼及api介紹使用

4、總結一次請求及響應的真實過程

5、歡迎點選我的部落格及GitHub — 部落格提供RSS訂閱哦