轉(zhuǎn)自其他平臺
https://blog.csdn.net/hejingyuan6/article/details/30273879
Servlet由來
做過BS項(xiàng)目的人都知道,瀏覽器能夠根據(jù)HTML靜態(tài)標(biāo)記語言來顯示各式各樣的網(wǎng)頁。但是如果我們需要在網(wǎng)頁上完成一些業(yè)務(wù)邏輯:比如登陸驗(yàn)證。或者說網(wǎng)頁顯示的內(nèi)容在服務(wù)器的數(shù)據(jù)庫中。如果是這樣,除了負(fù)責(zé)顯示的HTML標(biāo)記之外,必須還要有完成這些業(yè)務(wù)功能的代碼存在。這種網(wǎng)頁我們就叫做動態(tài)網(wǎng)頁。
對于靜態(tài)網(wǎng)頁而言,服務(wù)器上存在的是一個個純HTML文件。當(dāng)客戶端瀏覽器發(fā)出HTTP請求時,服務(wù)器可以根據(jù)請求的URL找到對應(yīng)的HTML文件,并將HTML代碼返回給客戶端瀏覽器。
但是對于動態(tài)網(wǎng)頁,服務(wù)器上除了找到需要顯示的HTML標(biāo)記外,還必須執(zhí)行所需要的業(yè)務(wù)邏輯,然后將業(yè)務(wù)邏輯運(yùn)算后的結(jié)果和需要顯示的HTML標(biāo)記一起生成新的HTML代碼。最后將新的帶有業(yè)務(wù)邏輯運(yùn)算結(jié)果的HTML代碼返回給客戶端。
為了實(shí)現(xiàn)動態(tài)網(wǎng)頁的目標(biāo),JavaServlet技術(shù)因應(yīng)而生,它能夠以一種可移植的方法來提供動態(tài)的、面向用戶的內(nèi)容。
簡單來說:
servlet是在服務(wù)器上運(yùn)行的小程序。Servlet的主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動態(tài)Web內(nèi)容,是為web開發(fā)服務(wù)的。
CGI與Servlet對比
開始的時候,公共網(wǎng)關(guān)接口(CommonGateway Interface,CGI)腳本是生成動態(tài)內(nèi)容的主要技術(shù)。雖然使用得非常廣泛,但CGI腳本技術(shù)有很多的缺陷,這包括平臺相關(guān)性和缺乏可擴(kuò)展性。為了避免這些局限性,JavaServlet技術(shù)因應(yīng)而生,它能夠以一種可移植的方法來提供動態(tài)的、面向用戶的內(nèi)容。處理用戶請求。
對比一:當(dāng)用戶瀏覽器發(fā)出一個Http/CGI的請求,或者說調(diào)用一個CGI程序的時候,服務(wù)器端就要新啟用一個進(jìn)程(而且是每次都要調(diào)用),調(diào)用CGI程序越多(特別是訪問量高的時候),就要消耗系統(tǒng)越多的處理時間,只剩下越來越少的系統(tǒng)資源,對于用戶來說,只能是漫長的等待服務(wù)器端的返回頁面了,這對于電子商務(wù)激烈發(fā)展的今天來說,不能不說是一種技術(shù)上的遺憾。
而Servlet充分發(fā)揮了服務(wù)器端的資源并高效的利用。每次調(diào)用Servlet時并不是新啟用一個進(jìn)程,而是在一個Web服務(wù)器的進(jìn)程中共享和分離線程,而線程最大的好處在于可以共享一個數(shù)據(jù)源,使系統(tǒng)資源被有效利用。故servlet不是線程安全的,單實(shí)例多線程的
對比二:傳統(tǒng)的CGI程序,不具備平臺無關(guān)性特征,系統(tǒng)環(huán)境發(fā)生變化,CGI程序就要癱瘓,而Servlet具備Java的平臺無關(guān)性,在系統(tǒng)開發(fā)過程中保持了系統(tǒng)的可擴(kuò)展性、高效性。
對比三:傳統(tǒng)技術(shù)中,一般大都為二層的系統(tǒng)架構(gòu),即Web服務(wù)器+數(shù)據(jù)庫服務(wù)器,導(dǎo)致網(wǎng)站訪問量大的時候,無法克服CGI程序與數(shù)據(jù)庫建立連接時速度慢的瓶頸,從而死機(jī)、數(shù)據(jù)庫死鎖現(xiàn)象頻繁發(fā)生。而我們的Servlet有連接池的概念,它可以利用多線程的優(yōu)點(diǎn),在系統(tǒng)緩存中事先建立好若干與數(shù)據(jù)庫的連接,到時候若想和數(shù)據(jù)庫打交道可以隨時跟系統(tǒng)"要"一個連接即可,反應(yīng)速度可想而知。
Servlet的運(yùn)行過程
- ⒈ 客戶端發(fā)送請求至服務(wù)器端;
- ⒉服務(wù)器端根據(jù)web.xml文件中的Servlet相關(guān)配置信息,將客戶端請求轉(zhuǎn)發(fā)到相應(yīng)的Servlet
- ⒊ Servlet引擎調(diào)用Service()方法,根據(jù)request對象中封裝的用戶請求與數(shù)據(jù)庫進(jìn)行交互,返回?cái)?shù)據(jù)之后,Servlet會將返回的數(shù)據(jù)封裝到response對象中;
- ⒋ Servlet生成響應(yīng)內(nèi)容并將其傳給服務(wù)器。響應(yīng)內(nèi)容動態(tài)生成,通常取決于客戶端的請求
-
⒌ 服務(wù)器將響應(yīng)返回給客戶端
Servlet的運(yùn)行過程
Servlet生命周期
- 加載和實(shí)例化;在第一次請求Servlet時,Servlet容器將會創(chuàng)建Servlet實(shí)例;
- 初始化;Servlet容器加載完成Servlet之后,必須進(jìn)行初始化,此時,init方法將被調(diào)用;
- Servlet初始化之后,就處于響應(yīng)請求的就緒狀態(tài),此時如有客戶端請求發(fā)送,就會調(diào)用Servlet實(shí)例的service()方法,并且根據(jù)用戶的請求方式,調(diào)用doPost或者doGet方法;
- 最后,Servlet容器負(fù)責(zé)將Servlet實(shí)例進(jìn)行銷毀,調(diào)用destroy方法實(shí)現(xiàn);
對于更多的客戶端請求,Server創(chuàng)建新的請求和響應(yīng)對象,仍然激活此Servlet的service()方法,將這兩個對象作為參數(shù)傳遞給它。如此重復(fù)以上的循環(huán),但無需再次調(diào)用init()方法。
一般Servlet只初始化一次(只有一個對象),當(dāng)Server不再需要Servlet時(一般當(dāng)Server關(guān)閉時),Server調(diào)用Servlet的Destroy()方法。
實(shí)例解析:
html代碼--客戶端瀏覽器
<span style="font-family:KaiTi_GB2312;"><html>
<head>
<title>學(xué)生管理</title>
</head>
<body>
<h1>根據(jù)出生日期段查詢</h1>
<form action="queryStudentServlet">
出生日期 :<input type="text" name="beginDate">至<input type="text" name="endDate">
<input type="submit" value="查詢學(xué)生">
</form>
</body>
</html>
</span>
配置文件
<span style="font-family:KaiTi_GB2312;"><servlet>
<servlet-name>StudentMgrServlet</servlet-name>
<servlet-class>StudentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StudentMgrServlet</servlet-name>
<url-pattern>/queryStudentServlet</url-pattern>
</servlet-mapping>
</span>
Servlet處理過程
<span style="font-family:KaiTi_GB2312;"> import java.text.*;
import java.util.*;
import java.io.*;
import javax.servlet.http.*;
import javax.servlet.*;
import com.bjpowernode.exam.model.*;
import com.bjpowernode.exam.manager.*;
public class StudentServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String sBeginDate = request.getParameter("beginDate");
String sEndDate = request.getParameter("endDate");
Date beginDate = new Date();
Date endDate = new Date();
try {
beginDate = new SimpleDateFormat("yyyy-MM-dd").parse(sBeginDate);
endDate = new SimpleDateFormat("yyyy-MM-dd").parse(sEndDate);
}catch(Exception e) {
e.printStackTrace();
}
StudentManager studentManager = new StudentManagerImpl();
List<Student> studentList = studentManager.findStudentList(beginDate, endDate);
//表格省略…
}
}
</span>
Servlet如何同時處理多個請求?
Servlet采用多線程來處理多個請求的同時訪問。Servlet容器通過線程池來管理維護(hù)服務(wù)請求。所謂線程池,相當(dāng)于數(shù)據(jù)庫連接池,實(shí)際上是等待執(zhí)行代碼的一組線程,叫做工作者線程。Servlet容器通過一個調(diào)度線程來管理工作者線程。
- 當(dāng)容器收到一個Servlet的訪問請求,調(diào)度者線程就從線程池中選出一個工作者線程,將用戶請求傳遞給該線程,然后由該線程處理Servlet的service()方法;
- 當(dāng)這個線程在執(zhí)行的時候,容器收到一個新的請求,調(diào)度者線程再次從線程池中選出一個新的工作者線程;
- 當(dāng)容器同時收到對同一個Servlet的多個請求時,那么Servlet的service方法將在多線程中并發(fā)執(zhí)行。
注:
1. Servlet容器默認(rèn)采用單實(shí)例多線程的方式來處理請求。這樣減少了產(chǎn)生Servlet實(shí)例的開銷,提升了對請求的響應(yīng)時間;
2. 對于Tomcat容器來講,可以在其server.xml中通過<Connector>中設(shè)置線程池中的線程數(shù)目。
如何開發(fā)線程安全的Servlet?
Servlet容器采用多線程來處理請求,提高性能的同時也造成了線程安全問題。要開發(fā)線程安全的Servlet應(yīng)該從一下幾個方面進(jìn)行:
- 變量的線程安全; 多線程并不共享局部變量,所以我們要盡可能的在Servlet中使用局部變量;
- 代碼塊的線程安全; 使用同步塊Synchronized,防止可能調(diào)用的代碼塊;但是要注意的是,要盡可能得縮小同步代碼的方范圍,不要在service方法和響應(yīng)方法上直接使用同步,這會嚴(yán)重影響性能。
- 屬性的線程安全; ServletContext,HttpSession,ServletRequest對象中屬性;
- 使用同步集合; 使用Vector代替ArrayList,使用HashTable代替HashMap;
- 不要在Servlet中創(chuàng)建自己的線程來完成某個功能; Servlet本身就是多線程的,如果再創(chuàng)建新的線程,將會導(dǎo)致線程執(zhí)行復(fù)雜化,出現(xiàn)線程安全問題;
- 在多個Servlet中,對外部對象,比如:文件;進(jìn)行修改操作一定要加鎖,做到互斥訪問;
總結(jié):
一個servlet就是Java編程語言中的一個類,它被用來擴(kuò)展服務(wù)器的性能,服務(wù)器上駐留著可以通過“請求-響應(yīng)”編程模型來訪問的應(yīng)用程序。Servlet通過解析http請求,取得客戶端的參數(shù)來進(jìn)行下一步操作。其實(shí)簡單來說,servlet就是一個控制器,取參數(shù),調(diào)用業(yè)務(wù)邏輯.
而在.net 中HttpHandler是一個HTTP請求的真正處理中心,也正是在這個HttpHandler容器中,ASP.NET Framework才真正地對客戶端請求的服務(wù)器頁面做出編譯和執(zhí)行,并將處理過后的信息附加在HTTP請求信息流中再次返回到HttpModule中。