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

http伺服器是web伺服器的一種,也是開發最常見的,自然還有其他方式進行資訊互動,比如ftp檔案伺服器…
web伺服器是可以向送出請求的浏覽器提供文檔的程式。其核心過程為 連接配接過程 — 請求過程 — 應答過程 — 關閉連接配接
這讓我想到了tomcat架構的一張圖:
如圖,tomcat 包含了核心服務子產品:connector連接配接子產品 和 container 容器。tomcat server 核心是一個 servlet/jsp container。對每一個http請求,過程如下
— 擷取連接配接 — servlet來分析請求(httpservletrequest) — 調用其service方法,進行業務處理 — 産生相應的響應(httpservletresponse) — 關閉連接配接
如圖:
藍色線指向過程是請求,綠色線指向過程是響應過程。也就是上面web伺服器核心過程:“連接配接過程 — 請求過程 — 應答過程 — 關閉連接配接”
什麼是servlet?(每次都會不停的問自己,這是什麼“what”?緊接着應該是什麼用“how”吧)
“servlet 是運作在web伺服器的java小程式。servlet可以擷取并針對web用戶端的請求作出響應。一般情況下,通過http,即超文本傳輸協定,進行傳輸通信。” <a href="http://www.bysocket.com/?p=518#">?</a> 1 <code>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.</code>
是以,servlet 是web伺服器核心工作的抽象。它不單單隻是實作httpservlet,可能實作有ftpservlet(這個我猜的)等。相對較多的web開發,知道的肯定是httpservlet。
補充,在servlet規範是這樣寫道的:
serlvet是基于java技術的web元件,容器托管的,用于生産動态内容。它也是基于平台無關的java類格式,被編譯為平台無關的位元組碼,可以被基于java技術的web server動态加載并運作。這裡容器,有時候也稱為servlet 引擎。
“httpservlet 提供了一個能被繼承後建立一個适應web網站的http servlet的抽象類。” <code>provides an abstract class to be subclassed to create an http servlet suitable for a web site.</code>
光說不練假把式,練一個“hello,servlet/jsp world!”:
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
<code>import</code> <code>java.io.ioexception;</code>
<code>import</code> <code>java.io.printwriter;</code>
<code>import</code> <code>javax.servlet.servletexception;</code>
<code>import</code> <code>javax.servlet.annotation.webservlet;</code>
<code>import</code> <code>javax.servlet.http.httpservlet;</code>
<code>import</code> <code>javax.servlet.http.httpservletrequest;</code>
<code>import</code> <code>javax.servlet.http.httpservletresponse;</code>
<code>/*</code>
<code> </code><code>* copyright [2015] [jeff lee]</code>
<code> </code><code>*</code>
<code> </code><code>* licensed under the apache license, version 2.0 (the "license");</code>
<code> </code><code>* you may not use this file except in compliance with the license.</code>
<code> </code><code>* you may obtain a copy of the license at</code>
<code> </code><code>* unless required by applicable law or agreed to in writing, software</code>
<code> </code><code>* distributed under the license is distributed on an "as is" basis,</code>
<code> </code><code>* without warranties or conditions of any kind, either express or implied.</code>
<code> </code><code>* see the license for the specific language governing permissions and</code>
<code> </code><code>* limitations under the license.</code>
<code> </code><code>*/</code>
<code>/**</code>
<code> </code><code>* @author jeff lee</code>
<code> </code><code>* @since 2015-6-25 19:46:45</code>
<code> </code><code>* hellowrold案例</code>
<code>@webservlet</code><code>(urlpatterns =</code><code>"/helloworld.html"</code><code>)</code>
<code>public</code> <code>class</code> <code>helloworldservlett</code><code>extends</code> <code>httpservlet{</code>
<code> </code>
<code> </code><code>private</code> <code>static</code> <code>final</code> <code>long</code> <code>serialversionuid = 1l;</code>
<code> </code><code>@override</code>
<code> </code><code>protected</code> <code>void</code> <code>doget(httpservletrequest req, httpservletresponse resp)</code>
<code> </code><code>throws</code> <code>servletexception, ioexception{</code>
<code> </code><code>// 擷取輸出列印對象</code>
<code> </code><code>printwriter out = resp.getwriter();</code>
<code> </code><code>out.println(</code><code>"hello,servlet/jsp world!"</code><code>);</code>
<code> </code><code>}</code>
<code>}</code>
右鍵該helloworldservlett.java檔案 — run as — run on server — 選擇tomcat伺服器 — finish即可
等待片刻,你可看到網頁上如下輸出。這就是用戶端從httpservlet擷取到的響應:
休息一下吧~ 看看小廣告:
<code>@webservlet(urlpatterns = "/helloworld.html")</code>
@webservlet 注解用于聲明一個httpservlet的配置。其中,urlpatters = “/helloworld.html”,urlpatterns複數形式,說明至少一個url必須被申明。它和另一個value必須存在一個,但不能同時存在。如果要比對多個url路徑的話,如下:
<code>@webservlet(urlpatterns = { "/helloworld01.html", "/helloworld02.html" }</code>
下面有個@override,重寫了父類httpservlet的doget方法。我們先看看父類httpservlet。httpservlet是一個抽象類,它提供了以下方法:
— doget , 服務于 htpp get 請求 — dopost , 服務于 http post 請求 — doput , 服務于 http put 請求 — dodelete,服務于 http delete 請求 …
對于不同的請求,httpservlet的子類必須相應的實作至少一個方法,通常來說,會是其中一個,這樣代碼比較清晰。那父類的doget方法做了什麼工作呢?
<code>protected void doget(httpservletrequest req, httpservletresponse resp)</code>
<code> </code><code>throws servletexception, ioexception</code>
<code> </code><code>{</code>
<code> </code><code>string protocol = req.getprotocol();</code>
<code> </code><code>string msg = lstrings.getstring("http.method_get_not_supported");</code>
<code> </code><code>if (protocol.endswith("1.1")) {</code>
<code> </code><code>resp.senderror(httpservletresponse.sc_method_not_allowed, msg);</code>
<code> </code><code>} else {</code>
<code> </code><code>resp.senderror(httpservletresponse.sc_bad_request, msg);</code>
<code> </code><code>}</code>
這裡就簡單的擷取了下http協定及http local資訊,然後可以協定是否是1.1,做出分别是405或者400http狀态碼的響應。
回到helloworldservlett.java 這裡:
<code>@override</code>
<code> </code><code>throws servletexception, ioexception {</code>
<code> </code><code>// 擷取輸出列印對象</code>
<code> </code><code>printwriter out = resp.getwriter();</code>
<code> </code><code>out.println("hello,servlet/jsp world!");</code>
表示該helloworldservlett會接受http get請求,并oom到httpservletrequest,并執行裡面的邏輯代碼和傳回響應。 這裡從httpservletresponse對象中擷取到輸出列印對象printwriter,然後輸出了“hello,servlet/jsp world!”。
完畢!哦還有一點補充補充補充:
print,這裡還好一句話。如果列印個table會很麻煩,是以有一個jsp的東西出現了,是servlet的html化身。
又回到這個簡單的 get servlet代碼:
<code>public class helloworldservlett extends httpservlet{</code>
<code> </code><code>private static final long serialversionuid = 1l;</code>
<code> </code><code>protected void doget(httpservletrequest req, httpservletresponse resp)</code>
<code> </code><code>throws servletexception, ioexception{</code>
<code> </code><code>out.println("hello,servlet/jsp world!");</code>
這過程總結如下:
— 從浏覽器(client)擷取連接配接”/helloworld.html” — tomcat connector子產品将請求(request)傳遞給 container子產品 — container 子產品會做以下事情 —— 分析htpp請求資訊,組裝成httpservletrequest對象 —— 建立新的httpservletresponse對象 —— 根據路由配置,搜尋相應的servlet,并建立一個線程用于處理本次請求。此時線程會将上面request和response對象的索引,傳遞給servlet — 新線程中的servlet處理邏輯 — 線程結束後,通過httpservletresponse對象的printwriter,傳回浏覽器一個資訊
過程圖如下:
藍色線指向過程是請求,綠色線指向過程是響應過程,橙色線指向過程是内部處理過程。
有些面試題會這樣問:
servlet是線程安全的嗎? 不是,一個servlet實作類隻會有一個執行個體對象,多個線程是可能會通路同一個servlet執行個體對象的,線程安全問題都是由全局變量及靜态變量引起的。
是以,servlet對象執行個體化是在以第一次請求此servlet時,如果通路後,執行個體對象存在記憶體中,隻會在伺服器停止時,它才會消失。它不會随着各個線程結束而結束。是以下次通路servlet時,servlet container會搜尋相應的servlet,如果不存在,container建立相應的servlet。這也是我們想要的結果。
再來個惡心的面試題:
servlet是單例嗎? 不一定是,在一個serveltname情況下是的。在多個servletname比對到一個servlet類時,該servlet不是單例。
發現這一部落格寫的太多,回頭一看。可以寫成三個文章了。言歸正傳本文要點如下
1、簡單介紹web伺服器 及 tomcat容器 2、第一個sevlet的開發及使用 3、深入源碼及api介紹使用 4、總結一次請求及響應的真實過程 5、歡迎點選我的部落格及github — 部落格提供rss訂閱哦