Servlet&JSP的那些事兒(六)

來源:互聯網
上載者:User

什麼是屬性?

在Servlet&JSP的那些事兒(五)中,我們瞭解了ServletContext監聽者如何在擷取上下文初始化參數後建立一個對象,以及如何將對象作為一個屬性儲存區到ServletContext,以便web應用的其他部分能得到該對象。屬性就是一個對象,設定(或稱之為綁定)到另外3個servlet
API對象中-SservletContext、HttpServletRequest(或HttpServletResponse)、HttpSession。可以把它簡單的認為是一個映射執行個體對象中的名/值對(名是一個String,值是一個Object)。在實際中,我們不關心它如何?,只關心屬性的範圍。通俗的講,就是看它能活多久。

屬性和參數的區別

屬性不是參數,它們之間的區別如表1。

  屬性 參數
類型 應用/上下文
請求
會話(註:沒有特定於servlet的屬性,只需要使用執行個體變數。)
應用/上下文初始化參數
請求參數
servlet初始化參數(註:沒有會話參數的說法。)
設定方法 setAttribute(String name, Object value) 不能設定應用和servlet初始化參數,他們都在web.xml中設定。
傳回型別 Object String
擷取方法 getAttribute(String name)(註:不要忘了強制轉換,因為傳回型別是Object) getInitParameter(String name)

表1 屬性和參數的區別

三個範圍:上下文、請求和會話

內容屬性,web應用中的每一部分都能訪問。會話屬性,只有能訪問特定HttpSession的部分才能訪問。而請求屬性,只有能訪問特定ServletRequest的部分才能訪問。具體的範圍見表2。

  可訪問性
(誰能看到)
範圍
(能存活多久)
適用性
Context(上下文)
(不是安全執行緒的)
web應用的所有部分,包括servlet,jsp,servlet-contextlistener等。 ServletContext的生命週期,這意味著所部屬應用的生命期。如果伺服器或應用關閉,上下文則撤銷,其屬性也相應撤銷。 你希望整個應用共用的資源,包括資料庫連接、JNDJ尋找名、email地址等。
HttpSession(會話)
(不是安全執行緒的)
訪問這個特定會話的所有servlet或jsp。注意,會話從一個客戶請求擴充到可能跨同一個客戶的多個請求,這些請求可能到達多個servlet。 會話的生命期。會話可以通過編程撤銷,也可能只是因為逾時而撤銷。 與客戶會話有關的資源和資料,而不只是與一個請求相關的資源。它要與客戶完成一個持續的會話。購物車是一個典型例子。
Request(請求)
(是安全執行緒的)
應用中能直接存取請求對象的所有部分。基本上說,這意味著接收所轉寄請求的jsp和servlet(使用RequestDispatcher),另外還有與請求相關的監聽者。 請求的生命週期。這說明會持續到servlet的service()方法結束。也即,線程/棧處理這個請求的生命週期。 將模型資訊從控制器傳遞到視圖,或者傳遞特定於客戶請求的任何資料。
表2 屬性範圍

上下文範圍不是安全的

因為應用中的每一部分都能訪問內容屬性,而這意味著可能有多個servlet。多個servlet則說明你可能有多個線程,因為請求時並發處理的,每個請求在一個單獨的線程中處理。例如如下語句:

getServletContext().setAttribute("boo","12");getServletContext().setAttribute("foo","24");out.println(getServletContext().getAttribute("boo"));out.println(getServletContext().getAttribute("foo"));

在一個複雜項目中啟動並執行時候,第一次啟動並執行時候,可能會輸出預期結果12 24,第二次輸出可能會是12,,36了。可能的原因是:servlet A設定了內容屬性"boo"的值為"12","foo"的值為"24"。之後線程B,即servlet B成為活動線程(此時線程A回到可運行但未啟動並執行狀態),並設定內容屬性"foo"的值為"36"(值"24"丟了)。這時線程A又重新成為活動線程,它取得"foo"的值,結果就輸出了36。

如何讓內容屬性做到安全執行緒?

既然內容屬性不是安全執行緒的,那麼我們該如何改進呢?有人說使用同步服務的方法。也即對doGet方法做如下修改:

public synchronized void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException {response.setContentType("text/html;charset=utf-8");         PrintWriter out=response.getWriter();getServletContext().setAttribute("boo","12");getServletContext().setAttribute("foo","24");out.println(getServletContext().getAttribute("boo"));out.println(getServletContext().getAttribute("foo"));}

即給doGet方法添加synchronized關鍵字。但此方法意味著servlet中一次只能運行一個線程,但是並不能阻止其他servlet或jsp訪問這個屬性。同步服務方法會防止同一個servlet中的其他線程訪問內容屬性,但是不能阻止另外一個servlet的訪問。所以,不是需要對servlet加鎖,而是需要對上下文加鎖,也即,應該做如下修改:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException {response.setContentType("text/html;charset=utf-8");         PrintWriter out=response.getWriter();synchronized(getServletContext()) {getServletContext().setAttribute("boo","12");getServletContext().setAttribute("foo","24");out.println(getServletContext().getAttribute("boo"));out.println(getServletContext().getAttribute("foo"));}}

保護內容屬性的一般做法是對內容物件本身同步,如果訪問內容相關的每一個人都必須先得到內容物件的鎖,就能保證一次只有一個線程可以得到或設定內容屬性。但是,只有當處理這些內容屬性的其他代碼也對ServletContext同步時,這種做法才起作用。如果一段代碼沒有請求鎖,那麼這段代碼還是能自由訪問內容屬性。

會話屬性是安全的嗎?

貌似還沒有介紹會話呢。會話會在下一篇討論。其實會話就是一個對象,用於維護與一個使用者的工作階段狀態。對於同一個使用者的多個請求,會話會跨這些請求持久儲存。先來看看只有一個使用者的情況,如果只有一個使用者,而且一個客戶一次只有一個請求,這就說明會話是安全執行緒的嗎?會有一個使用者一次有多個請求的情況發生嗎?元芳,你怎麼看?

使用者有可能開啟一個新的瀏覽器視窗,在這種情況下,容器還是為一個使用者使用同樣的會話,儘管它來自另一個瀏覽器執行個體。所以,會話屬性不是安全執行緒的。那麼如何保護這些會話屬性不受多線程的破壞呢?呵呵,只需要像內容屬性一樣,對所有訪問這些會話屬性的代碼都進行同步即可。那麼,該對誰同步呢?必須對HttpSession同步!代碼如下

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,IOException {response.setContentType("text/html;charset=utf-8");         PrintWriter out=response.getWriter();HttpSession session = request.getSession();synchronized(session) {session .setAttribute("boo","12");session .setAttribute("foo","24");out.println(getServletContext().getAttribute("boo"));out.println(getServletContext().getAttribute("foo"));}}

為了防止同步產生大量的開銷,所以,一定要在最短的時間內完成同步目標,要讓同步塊儘可能小。

轉載請註明出處:http://blog.csdn.net/iAm333

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.