圖解 & 深刻淺出 JavaWeb:Servlet必會必知

Writer      :BYSocket(泥沙磚瓦漿木匠)html

微         博:BYSocket java

豆         瓣:BYSocket git

FaceBook:BYSocket github

Twitter    :BYSocket web

「眨眼間,離上一篇寫技術博文時隔1個月。怕本身真的生疏了,都是備案太慢惹得。哈哈,繼續high~ 」面試

[JavaEE 要懂的小事] Http相關 ,一直想寫點Web開發相關的。最近項目接口開發緊,還有準備新的九月份戰鬥。JDK IO源碼就隔一段落,溫故知新看看Servlet & JSP 相關。把本身基礎累積回顧一遍,並和你們分享分享一些心得和代碼。這裏應該涉及到一部分源碼,開發思想和一些手工作出的圖。喜歡java,或者有必定Java開發經驗的多提寶貴意見。express

1、Web服務器

從事web開發的人,會很清楚一個東西叫 Web服務器,好比JEE開發—TomcatJetty,.NET開發—ISS等。HTTP服務器是使用 HTTP(超文本傳輸協議) 與客戶機瀏覽器進行信息交流。下面就是HTTP服務器簡單交互圖:(來自[JavaEE 要懂的小事] Http相關 博客)apache

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

HTTP服務器Web服務器的一種,也是開發最多見的,天然還有其餘方式進行信息交互,好比FTP文件服務器小程序

Web服務器是能夠向發出請求的瀏覽器提供文檔的程序。其核心過程爲api

    鏈接過程 — 請求過程 — 應答過程 — 關閉鏈接

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

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

2、Tomcat 簡單說幾句

如圖,Tomcat 包含了核心服務模塊:Connector鏈接模塊 和 Container 容器。Tomcat Server 核心是一個 Servlet/JSP Container。對每個HTTP請求,過程以下

獲取鏈接

Servlet來分析請求HttpServletRequest

— 調用其service方法,進行業務處理

— 產生相應的響應HttpServletResponse

關閉鏈接

如圖:

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

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

3、我第一個Servlet

什麼是Servlet?(每次都會不停的問本身,這是什麼「What」?緊接着應該是什麼用「How」吧)

JavaEE 6文檔中,介紹以下

Servlet 是運行在Web服務器的Java小程序。Servlet能夠獲取並針對Web客戶端的請求做出響應。通常狀況下,經過HTTP,即超文本傳輸協議,進行傳輸通訊。」

?

1
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的抽象類。」

?

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

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

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
  *
  *
  * 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便可

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

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

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

休息一下吧~ 看看小廣告:

開源代碼都在個人gitHub上哦 — https://github.com/JeffLi1993

3、分析源碼


?

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

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

?

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

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

— doGet  , 服務於 HTPP GET 請求

— doPost , 服務於 HTTP POST 請求

— doPut  , 服務於 HTTP PUT 請求

— doDelete,服務於 HTTP DELETE 請求

如圖:

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

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

?

1
2
3
4
5
6
7
8
9
10
11
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 這裏:

?

1
2
3
4
5
6
7
@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化身。

5、深刻Servlet 具體過程

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

?

1
2
3
4
5
6
7
8
9
10
11
12
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,返回瀏覽器一個信息

過程圖以下:

圖解 & 深刻淺出 JavaWeb:Servlet必會必知

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

有些面試題會這樣問:

Servlet是線程安全的嗎?

不是,一個servlet實現類只會有一個實例對象,多個線程是可能會訪問同一個servlet實例對象的,線程安全問題都是由全局變量靜態變量引發的。

所以,Servlet對象實例化是在以第一次請求此Servlet時,若是訪問後,實例對象存在內存中,只會在服務器中止時,它纔會消失。它不會隨着各個線程結束而結束。所以下次訪問Servlet時,Servlet Container會搜索相應的Servlet,若是不存在Container新建相應的Servlet。這也是咱們想要的結果。

再來個噁心的面試題:

Servlet是單例嗎?

不必定是,在一個ServeltName狀況下是的。在多個ServletName匹配到一個Servlet類時,該Servlet不是單例。

6、小結

發現這一博客寫的太多,回頭一看。能夠寫成三個文章了。言歸正傳本文要點以下

一、簡單介紹Web服務器 及 Tomcat容器

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

三、深刻源碼及api介紹使用

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

五、歡迎點擊個人博客及GitHub — 博客提供RSS訂閱哦

———- http://www.bysocket.com/ ————- https://github.com/JeffLi1993 ———-

相關文章
相關標籤/搜索