国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
servlet生命周期

第 14 章 生命周期

注意

講一下servlet的生命周期與運(yùn)行時(shí)的線程模型,對了解servlet的運(yùn)行原理有所幫助,這樣才能避免一些有沖突的設(shè)計(jì)。

如果你不滿足以下任一條件,請繼續(xù)閱讀,否則請?zhí)^此后的部分,進(jìn)入下一章:第 15 章 分頁。

  1. 了解servlet的生命周期。

  2. 了解servlet運(yùn)行時(shí)的線程模型,及設(shè)計(jì)程序時(shí)需要注意的部分。

14.1. 生命周期

我們之前使用的都是javax.servlet.http.HttpServlet,這個(gè)類實(shí)現(xiàn)了javax.servlet.Servlet接口,而這個(gè)接口中定義的三個(gè)方法是所有servlet都必須實(shí)現(xiàn)的。

package javax.servlet;public interface Servlet {void init(ServletConfig config);void service(ServletRequest request, ServletResponse response);void destroy();}

如圖所示,tomcat之類的服務(wù)器首先根據(jù)web.xml中的定義實(shí)例化servlet,然后調(diào)用它的init()方法進(jìn)行初始化,init()方法的ServletConfig參數(shù)是服務(wù)器傳遞進(jìn)servlet的,其中包含web.xml配置的初始化信息和ServletContext對象等共享內(nèi)容。

初始化后的servlet實(shí)例便進(jìn)入等待請求的狀態(tài),當(dāng)有與servlet-mapping匹配的請求進(jìn)入時(shí),服務(wù)器會(huì)調(diào)用servlet實(shí)例的service方法,傳入ServletRequest與ServletResponse兩個(gè)參數(shù)等待servlet處理完畢。

注意一點(diǎn),對于每個(gè)web應(yīng)用,內(nèi)存中只存在一個(gè)servlet實(shí)例,所有請求都是調(diào)用這個(gè)servlet實(shí)例,所以我們說servlet不是線程安全的,所有操作都要限制在service()方法中進(jìn)行,不要在servlet中定義類變量。(doGet()和doPost()是HttpServlet覆蓋service()方法后分支出來的輔助方法,實(shí)際上服務(wù)器調(diào)用的還是service()。)

當(dāng)web應(yīng)用卸載時(shí),服務(wù)器會(huì)調(diào)用每個(gè)已經(jīng)初始化的servlet的destroy(),然后銷毀這些servlet實(shí)例,如果你需要在servlet銷毀時(shí)釋放什么資源的話,可以寫在destory()方法中。

那么servlet是在什么時(shí)候進(jìn)行初始化的呢?我們可以通過web.xml中的load-on-startup標(biāo)簽。

<servlet><servlet-name>TestServlet</servlet-name><servlet-class>anni.TestServlet</servlet-class><load-on-startup>1</load-on-startup></servlet>

load-on-startup的值是一個(gè)整數(shù),當(dāng)它大于等于零的時(shí)候服務(wù)器會(huì)在web發(fā)布的時(shí)候初始化servlet。當(dāng)它小于零或者我們沒有設(shè)置load-on-startup的時(shí)候,服務(wù)器會(huì)在用戶第一次訪問servlet的時(shí)候才去初始化servlet。

或許你對load-on-startup為什么是一個(gè)整數(shù)存有疑問,為什么不是true和false呢?這是因?yàn)槿绻覀冊趙eb.xml中設(shè)置了多個(gè)servlet的時(shí)候,可以使用load-on-startup來指定servlet的加載順序,服務(wù)器會(huì)根據(jù)load-on-startup的大小依次對servlet進(jìn)行初始化。不過即使我們將load-on-startup設(shè)置重復(fù)也不會(huì)出現(xiàn)異常,服務(wù)器會(huì)自己決定初始化順序。

回頭看看javax.servlet.Filter中也有init()和destroy()方法,它的聲明周期與servlet基本一致,服務(wù)器使用init()對Filter初始化,銷毀Filter的時(shí)候調(diào)用destroy()方法,只是過濾器就不在有l(wèi)oad-on-startup設(shè)置了,它總是會(huì)在服務(wù)器啟動(dòng)的時(shí)候進(jìn)行初始化,然后按照web.xml定義的順序依次執(zhí)行。

14.2. 線程模型

我們做一個(gè)試驗(yàn),以此來證明某些編寫servlet的方法是絕對錯(cuò)誤的。

第一步,我們打開瀏覽器,瀏覽14-02的index.jsp頁面,輸入“叮咚”。

第二步,我們再打開一個(gè)14-02/index.jsp頁面,輸入“lingirl”。

第三步,點(diǎn)擊第一個(gè)頁面的提交按鈕,然后在10秒之內(nèi)點(diǎn)擊另一個(gè)頁面的提交按鈕,等兩個(gè)頁面都提交成功后,我們會(huì)看到如下頁面。

url上有亂碼這個(gè)就是提交“叮咚”的頁面,會(huì)驚訝吧?本來這時(shí)應(yīng)該顯示“叮咚”的。

這個(gè)頁面對應(yīng)提交“lingirl”的頁面,它似乎是顯示正常的。

到底是哪里出錯(cuò)了,為什么第一個(gè)頁面提交了數(shù)據(jù),卻得到第二個(gè)頁面提交的結(jié)果,首先讓我們看一下TestServlet的代碼。

package anni;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class TestServlet extends HttpServlet {private String username;public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {this.username = request.getParameter("username");try {Thread.sleep(10000);} catch(InterruptedException ex) {}response.getWriter().write(this.username);}}

doGet()方法中從request中獲得username參數(shù),然后賦給this.username,這是一個(gè)類變量。然后暫停10秒,這10秒我們假設(shè)正在進(jìn)行一些很費(fèi)時(shí)間的計(jì)算,這樣我們就有十秒鐘去點(diǎn)兩個(gè)頁面的提交按鈕了。最后將this.username寫入response。

你也許在想:“這沒有問題啊,第一個(gè)頁面提交了數(shù)據(jù),等待10秒返回,第二個(gè)頁面再提交數(shù)據(jù),等待10秒返回,兩者并不沖突啊。”可實(shí)際上在多線程模型中不會(huì)有這種隊(duì)列讓請求一個(gè)一個(gè)執(zhí)行,所有請求都是蜂擁而至。

在這個(gè)例子里,第一個(gè)請求過來將“叮咚”賦值給this.username后進(jìn)行等待,10秒之內(nèi)我們的第二個(gè)請求又調(diào)用了doGet()方法,并把this.username修改為“lingirl”,等到10秒后第一個(gè)請求結(jié)束等待后,獲得的this.username已經(jīng)是“lingirl”了。

this.username這種寫法在servlet中是絕對禁用的,如果有什么信息需要保存,可以考慮放到session或ServletContext中。

14.3. 在jsp中定義類變量

寫在<%%>之間的代碼,在轉(zhuǎn)換成servlet之后都會(huì)service()方法內(nèi)運(yùn)行,所以我們不必?fù)?dān)心出現(xiàn)上邊this.username的問題。

但是我們可以用<%!%>(注意多出來的感嘆號)定義類變量或類方法,把上一個(gè)罪大惡極的servlet改造成jsp的話,就像這樣。

<%@ page contentType="text/html; charset=gb2312"%><%!String username;%><%this.username = request.getParameter("username");try {Thread.sleep(10000);} catch(InterruptedException ex) {}out.write(this.username);%>

注意

使用14-03下的例子可以測試jsp出錯(cuò)的效果,記得要在10秒之內(nèi)點(diǎn)擊兩次。

<%!%>似乎是一個(gè)巨大的陷阱,如果我們使用它定義類變量就一定會(huì)出現(xiàn)多線程錯(cuò)誤。

不過凡事都有正反兩面,當(dāng)我們需要在jsp中定義一個(gè)通用方法時(shí),就需要借助<%!%>的力量了,假設(shè)我們需要一個(gè)方法,根據(jù)用戶的性別顯示不同的html內(nèi)容,如果sex = 0就輸出紅色的“男”,如果sex = 1就輸出綠色的“女”。為實(shí)現(xiàn)這個(gè)功能,我們可以定義一個(gè)sexRenderer()方法。

14-04/index.jsp頁面顯示效果如下:

index.jsp中的代碼分兩部分。

第一部分定義sexRenderer()方法和

<%!public String sexRenderer(int sex) {if (sex == 0) {return "<span style='color:red;'>男</span>";} else if (sex == 1) {return "<span style='color:green;'>女</span>";} else {return "";}}%>

第二部分循環(huán)顯示保存了性別信息的數(shù)組,顯示的時(shí)候?qū)?huì)調(diào)用sexRenderer()方法。

<%int[] people = {0, 1, 1, 0};for (int i = 0; i < this.people.length; i++) {%><tr><td><%=this.sexRenderer(this.people[i])%></td></tr><%}%>

好的,現(xiàn)在我們知道可以在<%!%>中定義方法和變量了。但是同時(shí)也要了解的是<%!%>已經(jīng)脫離了service()方法,這就導(dǎo)致不能在它里邊使用request,response這些默認(rèn)變量了,如果想要調(diào)用request只能寫成void doSomething(HttpServletRequest request)的形式了,稍微注意一下即可。

14.4. jsp九大默認(rèn)對象

分別是request, response, out, pageContext, session, application, page, config, exception。

讓我們看看它們與servlet中變量的對應(yīng)關(guān)系。

首先要明確的是,這九個(gè)變量都只在<%%>中有效,<%!%>中是無法調(diào)用這九個(gè)對象的。實(shí)際上<%%>最后會(huì)成為service()方法中的代碼,我們這里就看看如何在service()方法中獲得這些對象吧。

  1. request

    public void service(ServletRequest req, ServletResponse res) {    HttpServletRequest request  = (HttpServletRequest) req;    }    

    jsp中的request就是service()中傳入的req參數(shù),因?yàn)閟ervice中定義的是ServletRequest類型,我們還需要轉(zhuǎn)換成HttpServletRequest類型。

  2. response

    public void service(ServletRequest req, ServletResponse res) {    HttpServletResponse response  = (HttpServletResponse) res;    }    

    與上例相同,response也是service()中傳入的res參數(shù)。

  3. out

    Writer out = response.getWriter();    

    out對應(yīng)著從response中取出的writer對象,負(fù)責(zé)向響應(yīng)中輸出數(shù)據(jù)。不過jsp和servlet中的out還是有一點(diǎn)區(qū)別,雖然它們都實(shí)現(xiàn)了java.io.Writer接口,但servlet中實(shí)際類型是java.io.PrintWriter,而jsp中實(shí)際類型是javax.servlet.jsp.JspWriter。

  4. pageContext

    這是jsp獨(dú)有的,servlet里沒有page的概念。

  5. session

    HttpSession session = request.getSession();    

    直接從request中獲得會(huì)話。

  6. application

    ServletConext application = getServletConfig().getServletContext();    

    可以通過servletConfig獲得ServletContext,這是整個(gè)web應(yīng)用共享的一個(gè)對象。

  7. page

    Object page = this;    

    page就代表當(dāng)前jsp對象,也可以直接使用this引用。

  8. config

    ServletConfig config = getServletConfig();    

    這是在servlet初始化時(shí)由服務(wù)器傳入的對象,可以通過它獲得web.xml中定義的初始化參數(shù)。

  9. exception

    想在jsp中使用這個(gè)對象需要滿足一些條件了。

    首先我們要在14-05/index.jsp中故意拋出一個(gè)異常。

    <%@ page contentType="text/html; charset=gb2312" errorPage="error.jsp"%>    <%    String str = null;    str.length();    %>    

    str值是null,直接在null上調(diào)用length()方法會(huì)引發(fā)NullPointerException,然后我們可以看到頁面第一行使用jsp指令(directive)設(shè)置了errorPage="error.jsp",這樣在出現(xiàn)異常的時(shí)候就會(huì)自動(dòng)forward到error.jsp中?,F(xiàn)在看看error.jsp中有些什么。

    <%@ page contentType="text/html; charset=gb2312" isErrorPage="true"%>    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">    <html>    <head>    <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />    <title>index</title>    </head>    <body>    <%=exception%>    </body>    </html>    

    最主要的是在jsp指令(directive)中設(shè)置isErrorPage="true",這樣我們就可以在jsp中使用exception對象了,實(shí)際上這個(gè)異常是從request中取出來的。

到此為止,jsp九大默認(rèn)對象已經(jīng)講解完畢,其中常用的還是四個(gè)作用域?qū)?yīng)的對象,其他的了解即可。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
J2EE企業(yè)級開發(fā)學(xué)習(xí)筆記(7)
Servlet學(xué)習(xí)
Java面試題全集(中)
圖解JSP與Servlet的關(guān)系
JSP頁面中
JSP/Servlet 工作原理
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服