其他更多java基礎(chǔ)文章:
java基礎(chǔ)學(xué)習(xí)(目錄)
什么是Servlet
Servlet是一個特殊的Java類泥兰, 是運(yùn)行在 Web 服務(wù)器中的小型 Java 程序(即:服務(wù)器端的小應(yīng)用程序)。servlet 通常通過 HTTP(超文本傳輸協(xié)議)接收和響應(yīng)來自 Web 客戶端的請求昼浦。這個Java類必須繼承HttpServlet。每個Servlet可以響應(yīng)客戶端的請求筒主,Servlet提供不同的方法用于響應(yīng)客戶端請求关噪,例如doGet,doPost乌妙,doPut等
Tomcat與Servlet的關(guān)系
Tomcat 是Web應(yīng)用服務(wù)器,是一個Servlet/JSP容器. Tomcat 作為Servlet容器,負(fù)責(zé)處理客戶請求,把請求傳送給Servlet,并將Servlet的響應(yīng)傳送回給客戶.而Servlet是一種運(yùn)行在支持Java語言的服務(wù)器上的組件.使兔。
Servlet最常見的用途是擴(kuò)展Java Web服務(wù)器功能,提供非常安全的,可移植的,易于使用的CGI替代品。
從http協(xié)議中的請求和響應(yīng)可以得知冠胯,瀏覽器發(fā)出的請求是一個請求文本,而瀏覽器接收到的也應(yīng)該是一個響應(yīng)文本锦针。
- Tomcat將http請求文本接收并解析荠察,然后封裝成HttpServletRequest類型的request對象置蜀,所有的HTTP頭數(shù)據(jù)讀可以通過request對象調(diào)用對應(yīng)的方法查詢到。
- Tomcat同時會要響應(yīng)的信息封裝為HttpServletResponse類型的response對象悉盆,通過設(shè)置response屬性就可以控制要輸出到瀏覽器的內(nèi)容盯荤,然后將response交給tomcat,tomcat就會將其變成響應(yīng)文本的格式發(fā)送給瀏覽器焕盟。
Java Servlet API 是Servlet容器(tomcat)和servlet之間的接口秋秤,它定義了serlvet的各種方法,還定義了Servlet容器傳送給Servlet的對象類脚翘,其中最重要的就是ServletRequest和ServletResponse灼卢。
所以說我們在編寫servlet時,需要實(shí)現(xiàn)Servlet接口来农,按照其規(guī)范進(jìn)行操作鞋真。
Servlet執(zhí)行過程
在瀏覽器的地址欄輸入:http://ip:port/appNames/servlet
1)通過瀏覽器和ip:port和這個服務(wù)器建立連接。
2) 瀏覽器會生成一個請求數(shù)據(jù)包(路徑appNames/servlet)向服務(wù)器發(fā)送請求沃于。
3) 服務(wù)器收到請求數(shù)據(jù)包涩咖,分析請求資源路徑做精準(zhǔn)定位,通過請求的appName查找webapps文件下面的appName做匹配繁莹,匹配上了需要獲取web.xml中的servlet(mapping)檩互。
4) 服務(wù)器創(chuàng)建兩個對象:
第一個對象:請求對象咨演,該對象實(shí)現(xiàn)了HttpServletRequest接口闸昨,服務(wù)器會將請求數(shù)據(jù)包中的數(shù)據(jù)解析出來,存儲在該對象里。這樣做的好處是沒有必要理解http協(xié)議雪标,只需要讀取request零院。
第二個對象:響應(yīng)對象,實(shí)現(xiàn)了HttpServletResponse接口村刨,作用是servlet處理完成后的結(jié)果可以存放到該對象上告抄,然后服務(wù)器依據(jù)該對象的數(shù)據(jù)生成響應(yīng)數(shù)據(jù)包。
5) servlet在執(zhí)行servlet()方法時嵌牺,可以通過request獲取請求數(shù)據(jù)打洼,也可以將處理結(jié)果存放到response上。然后服務(wù)器與響應(yīng)對象直接形成一個默契逆粹,生成一個響應(yīng)數(shù)據(jù)包給瀏覽器募疮。
6)瀏覽器解析服務(wù)器返回的響應(yīng)數(shù)據(jù)包,生成響應(yīng)的結(jié)果僻弹。
Servlet訪問的過程:
Http請求---->web.xml--------> url -pattern----->servlet-name----->servlet-class-----> QuickStratServlet(對應(yīng)的Class文件)
Servlet的生命周期
Servlet生命周期可分為5個步驟
- 加載Servlet阿浓。當(dāng)Tomcat第一次訪問Servlet的時候,Tomcat會負(fù)責(zé)創(chuàng)建Servlet的實(shí)例
- 初始化蹋绽。當(dāng)Servlet被實(shí)例化后芭毙,Tomcat會調(diào)用init()方法初始化這個對象
- 處理服務(wù)筋蓖。當(dāng)瀏覽器訪問Servlet的時候,Servlet 會調(diào)用service()方法處理請求
- 銷毀退敦。當(dāng)Tomcat關(guān)閉時或者檢測到Servlet要從Tomcat刪除的時候會自動調(diào)用destroy()方法粘咖,讓該實(shí)例釋放掉所占的資源。一個Servlet如果長時間不被使用的話侈百,也會被Tomcat自動銷毀
- 卸載瓮下。當(dāng)Servlet調(diào)用完destroy()方法后,等待垃圾回收钝域。如果有需要再次使用這個Servlet讽坏,會重新調(diào)用init()方法進(jìn)行初始化操作。
簡單總結(jié):只要訪問Servlet网梢,service()就會被調(diào)用震缭。init()只有第一次訪問Servlet的時候才會被調(diào)用。
destroy()只有在Tomcat關(guān)閉的時候才會被調(diào)用战虏。
Servlet的配置
使用配置文件
- 寫Servlet類
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
}
}
-
在web.xml中配置Servlet
使用springboot
- 寫servlet類
- 在springboot啟動類配置
@SpringBootApplication
public class ServletApp {
@Bean
public ServletRegistrationBean MyServlet(){
return new ServletRegistrationBean(new MyServlet(),"/myserv/*");
}
public static void main(String[] args){
SpringApplication.run(ServletApp.class, args);
}
}
Servlet細(xì)節(jié)
-
Servlet的url匹配順序
當(dāng)一個請求發(fā)送到servlet容器的時候拣宰,容器先會將請求的url減去當(dāng)前應(yīng)用上下文的路徑作為servlet的映射url,比如我訪問的是http://localhost/hiway/user/aaa.html烦感,我的應(yīng)用上下文是hiway巡社,容器會將http://localhost/hiway去掉,剩下的/user/aaa.html部分拿來做servlet的映射匹配手趣。這個映射匹配過程是有順序的晌该,而且當(dāng)有一個servlet匹配成功以后,就不會去理會剩下的servlet了绿渣。其匹配規(guī)則和順序如下:
- 精確路徑匹配朝群。例子:比如servletA 的url-pattern為 /test,servletB的url-pattern為 /* 中符,這個時候姜胖,如果我訪問的url為http://localhost/test ,這個時候容器就會先進(jìn)行精確路徑匹配淀散,發(fā)現(xiàn)/test正好被servletA精確匹配右莱,那么就去調(diào)用servletA,也不會去理會其他的servlet了档插。
- 最長路徑匹配慢蜓。例子:servletA的url-pattern為/test/,而servletB的url-pattern為/test/a/郭膛,此時訪問http://localhost/test/a時晨抡,容器會選擇路徑最長的servlet來匹配,也就是這里的servletB。
- 擴(kuò)展匹配耘柱。如果url最后一段包含擴(kuò)展圆雁,容器將會根據(jù)擴(kuò)展選擇合適的servlet。例子:servletA的url-pattern:*.action
- 最后帆谍,如果前面三條規(guī)則都沒有找到一個servlet,容器會根據(jù)url選擇對應(yīng)的請求資源轴咱。如果應(yīng)用定義了一個default servlet汛蝙,則容器會將請求丟給default servlet
-
Servlet是單例的嗎
在Servlet規(guī)范中,對于Servlet單例與多例定義如下:
“Deployment Descriptor”, controls how the servlet container provides instances of the servlet.For a servlet not hosted in a distributed environment (the default), the servlet container must use only one instance per servlet declaration. However, for a servlet implementing the SingleThreadModel interface, the servlet container may instantiate multiple instances to handle a heavy request load and serialize requests to a particular instance.
上面規(guī)范提到:
如果一個Servlet沒有被部署在分布式的環(huán)境中朴肺,一般web.xml中聲明的一個Servlet只對應(yīng)一個實(shí)例窖剑。
而如果一個Servlet實(shí)現(xiàn)了SingleThreadModel接口,就會被初始化多個實(shí)例戈稿。默認(rèn)20個
所以個人理解Servlet不算單例西土,只是容器讓它只實(shí)例化一次,變現(xiàn)出來的是單例的效果而已
-
如何開發(fā)線程安全的Servlet
- 實(shí)現(xiàn) SingleThreadModel 接口
- 使用synchronized同步對共享數(shù)據(jù)的操作
- 避免使用實(shí)例變量
對上面的三種方法進(jìn)行測試鞍盗,可以表明用它們都能設(shè)計(jì)出線程安全的Servlet程序需了。但是,如果一個Servlet實(shí)現(xiàn)了SingleThreadModel接口般甲,Servlet引擎將為每個新的請求創(chuàng)建一個單獨(dú)的Servlet實(shí)例肋乍,這將引起大量的系統(tǒng)開銷。SingleThreadModel在Servlet2.4中已不再提倡使用敷存;同樣如果在程序中使用同步來保護(hù)要使用的共享的數(shù)據(jù)墓造,也會使系統(tǒng)的性能大大下降。這是因?yàn)楸煌降拇a塊在同一時刻只能有一個線程執(zhí)行它锚烦,使得其同時處理客戶請求的吞吐量降低觅闽,而且很多客戶處于阻塞狀態(tài)。另外為保證主存內(nèi)容和線程的工作內(nèi)存中的數(shù)據(jù)的一致性涮俄,要頻繁地刷新緩存,這也會大大地影響系統(tǒng)的性能蛉拙。所以在實(shí)際的開發(fā)中也應(yīng)避免或最小化 Servlet 中的同步代碼;在Serlet中避免使用實(shí)例變量是保證Servlet線程安全的最佳選擇禽拔。從Java 內(nèi)存模型也可以知道刘离,方法中的臨時變量是在棧上分配空間,而且每個線程都有自己私有的椂闷埽空間硫惕,所以它們不會影響線程的安全
學(xué)習(xí)資料:http://lixh1986.iteye.com/blog/2355692
-
Servlet的<load-on-startup>
在servlet的配置當(dāng)中,
<load-on-startup>1</load-on-startup>
的含義是:
標(biāo)記容器是否在啟動的時候就加載這個servlet野来。當(dāng)值為0或者大于0時恼除,表示容器在應(yīng)用啟動時就加載這個servlet;當(dāng)是一個負(fù)數(shù)時或者沒有指定時,則指示容器在該servlet被選擇時才加載豁辉。正數(shù)的值越小令野,啟動該servlet的優(yōu)先級越高。
配置load-on-startup后徽级,servlet在startup后立即加載气破,但只是調(diào)用servlet的init()方法,用以初始化該servlet相關(guān)的資源餐抢。初始化成功后现使,該servlet可響應(yīng)web請求;如未配置load-on-startup旷痕,容器一般在第一次響應(yīng)web請求時碳锈,會先檢測該servlet是否初始化,如未初始化欺抗,則調(diào)用servlet的init()先初始化售碳,初始化成功后,再響應(yīng)請求绞呈。
-
缺省default Servlet
可以將url-pattern 配置一個/贸人,代表該servlet是缺省的servlet。什么是缺省的servlet佃声?
當(dāng)你訪問資源地址所有的servlet都不匹配時灸姊,缺省的servlet賦值處理。其實(shí)秉溉,web應(yīng)用中所有的資源的響應(yīng)都是servlet負(fù)責(zé)力惯,包括靜態(tài)資源(html頁面)。(有配置缺省的servlet召嘶,無法訪問到靜態(tài)資源父晶。)
學(xué)習(xí)資料:https://www.cnblogs.com/zhangyinhua/p/7625851.html