kapok

          垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            455 隨筆 :: 0 文章 :: 76 評論 :: 0 Trackbacks
          http://www.uml.org.cn/j2ee/j2ee003.htm

          J2EE組件間共享對象技術
          作者:龔永生    本文選自:開放系統世界—賽迪網  2003年02月26日
          想要用好Struts應用框架,必須了解J2EE Web級JSP和Servlet技術存放共享對象的幾種方式。同時,要利用J2EE 開發Web應用程序也必須掌握組件間對象共享的機制。

          像Java程序有類級別變量、方法級別變量一樣,J2EE Web應用程序有四個對象存放共享對象。這些共享對象存放在那里,以便存放者或者其它程序代碼日后使用。這四個對象分別是頁面、請求、會話和應用程序,它們都是以數據結構鍵/值對的形式保存的。同時這四個對象形成了四個級別的共享對象存放地,即應用程序對象中的共享對象是全局性的,在整個應用程序的生命周期內有效(當然主動去掉除外),屬于所有的上網用戶;會話對象中的共享對象是在一個會話期內有效,屬于用戶的當前會話;請求對象中的共享對象在一個請求期內有效,屬于用戶發送的當前請求;頁面對象中的共享對象只屬于當前頁面的執行實例。本文主要分析共享對象的設置和訪問方法,包括共享對象的有效范圍、具體訪問方法、輔助顯示手段和多線程下的實現策略。

          在JSP中訪問共享對象


          Servlet運行時已經準備好了這些范圍對象,如表1所示。

          表1 JSP中的共享對象


             變量名 變量類名 對象可訪問范圍
          頁面 pageContext javax.servlet.jsp.PageContext 在執行某一個JSP時,Servlet運行時會為它初始化pageContext變量,這個變量可以被整個JSP代碼訪問,包括INCLUDE指示符插進來的代碼。
          請求 ruquest javax.servlet.http.HttpServletRequest 用戶提交一個HTTP請求給Servlet容量,Servlet運行時會把請求封裝成HttpServletRequest的一個實例,在JSP中表現為request變量。能訪問pageContext的JSP代碼也能訪問request,另外被處理這個請求的JSP代碼FORWARD到的JSP代碼也能訪問。
          會話 session javax.servlet.http.HttpSession 一個HttpSession會話由被創建到關閉或失效期間的用戶請求組成。處理這些請求的JSP可以訪問到這期間的session對象中的共享對象。在會話關閉或失效時,這些對象會丟失。
          應用程序 application javax.servlet.ServletContext 這個對象在應用程序的整個生命周期間都有效,存放在這個對象內的數據任何JSP都能訪問到。



          在Servlet中訪問共享對象


          Servlet中的共享對象如表2。

          表2 Servlet中的共享對象


          請求 SERVLET類的一系列服務方法的request參數。 javax.servlet.http.HttpServletRequest 用戶提交一個HTTP請求給Servlet容器,Servlet運行時會把請求封裝成HttpServletRequest的一個實例,并作為Servlet服務方法的request參數傳遞給Servlet。這個Servlet也可以把這個實例傳遞給其它Web組件。
          會話 request.getSession()或者request.getSession(boolesn)方法獲得。 javax.servlet.http.HttpSession 一個HttpSession會話由被創建到關閉或失敗期間的用戶請求組成。處理這些請求的Servlet可以訪問到這期間的session對象中的共享對象。在會話關閉或失效時,這些共享對象會丟失。
          應用程序 SERVLET的.getServletContext() javax.servlet.ServletContext 這個對象在應用程序的整個生命周期間都有效,存放在這個對象內的數據任何Web組件都能訪問到。



          資源組合


          在JSP技術中,有兩種把資源片斷組合成一個資源的技術:include 指示符和jsp:include元素。指示符的語法為:

          
          <%@ include file="fragmentresource.jsp" %>
          


          當一個JSP被翻譯成Servlet時,它會被處理。jsp:include元素的語法是:

          
          <jsp:include page="included.jsp"/>
          


          當這個JSP頁面被執行時,它會被處理。指示符是代碼的組合,元素則是結果的組合。fragmentresource.jsp和主頁面具有一樣的上下文,如頁面對象;而included.jsp不具有和主頁面一樣的頁面對象,但請求對象是同一個。

          在Servlet中,RequestDispatcher.include(request,response)實現結果的整合,示例代碼如下:

          
          RequestDispatcher dispatcher =request.getRequestDispatcher("/template.jsp");
          if (dispatcher !=null)
           dispatcher.include(request,response);
          


          控制傳遞


          在利用RequestDispatcher.forware(request,response)把控制傳給另一個Web組件設置形成一個控制管道時,要嚴格遵循“前面的組件處理request,最后的組件處理response”的準則。前面的組件甚至不能企圖獲取response輸出流的引用。這個控制管道中的組件具有同一個request對象,不具有相同的pageContext對象(針對JSP)。Servlet中傳遞控制的例子如下:

          
          RequestDispatcher dispatcher =request.getRequestDispatcher("/template.jsp");
          if (dispatcher !=null)
          dispatcher.forward(request,response);
          


          JSP中傳遞控制的例子如下:

          
          <jsp:forward page="/main.jsp"/>
          


          在JSP中,可以通過jsp:param元素來增加請求對象的參數,適用于jsp:include和jsp:forward兩元素。 示例如下:

          
          <jsp: forward page="included.jsp">
          <jsp:param name="param1 " value=="value1"/>
          </jsp:include>
          


          顯示共享對象




          圖1 顯示共享信息類圖


          在網頁上顯示各個級別的共享對象是一個非常不錯的調試手段。下面的顯示共享對象類圖(如圖1)實現了這個功能。它以類org.i18.struts.AttributeUtils為核心,這個類負責把四個對象的共享對象保存為鍵/值對的HashMap對象。通過它可以得到請求對象中的共享對象及參數信息,以及頁面對象、會話對象、應用對象這些共享對象的函數接口。在JSP頁面中,通過下面的代碼可以給這個類的對象提供輸入:

          
          <jsp:useBean id="bean3" scope="application"
          class="org.i18.struts.AttributeUtils" />
          <jsp:setProperty name="bean0" property="object" value="<%= pageContext %>" />
          


          JSP頁面可以利用Struts提供的logic標簽庫顯示這些共享對象:

          
          <li> 這是頁對象內的共享對象 </li>
          <table align="center" cellpadding="5" border="0">
          <tbody valign="center">
          <tr>
          <td class="header"> 共享對象名 </td>
          <td class="header"> 共享對象相關內容 </td>
          </tr>
           <logic:iterate id="element" name="bean0" property="pageProp"  >
          <tr><td>
           <bean:write name="element" property="key"/>
          </td>
          <td>
          <bean:write name="element" property="value"/>
          </tr>
          </logic:iterate>
          </tbody>
          </table>
          


          在Servlet中,AttributeDisplayHelper幫助者類完成JSP中logic標簽庫相應的功能。幫助者類完成工作后,AttrServlet把幫助者類完成的結果放在request中的一個共享屬性Attr中,接著把控制傳給servletAttr.jsp,再由它訪問AttrServlet在request中設置的共享屬性Attr,并顯示結果。

          使用者可以通過attr.jsp、AttrServlet的url映射和index.jsp的提交按鈕來查看當前上下文所有級別的共享對象。

          關于多線程問題


          J2EE系列規范中,EJB規范保證了組件開發者在單線程的環境下編程,但Servlet規范沒有規定Servlet的系列服務方法在單線程模式下運作,所以開發者在使用共享對象時要注意線程同步問題。一個比較通用的原則是:在一個專職的組件中設置共享對象,當設置和訪問破壞數據的一致性時,使用Java的同步控制。

          一個Servlet(包括JSP)的生命周期由其所在的容器控制。當有一個Servlet請求時,容器執行如下步驟:

          1.如果此Servlet的實例不存在,容器先裝載Servlet的類代碼,創建一個Servlet實例,接著調用這個實例的init方法。

          2.如果此Servlet的實例存在,容器分配一個處理用戶請求的工作線程。如果Servler實現了SingleThreadModel接口,工作線程會在這個實例上同步,并且在取得訪問權限后調用實例的service方法,否則直接調用實例的service方法。javax.servlet.http.HttpServlet的service方法會根據用戶的HTTP請求類型調用相應的doxxx方法。

          3.只有當所有的線程從這個實例中退出,容器在回收這個實例時才會調用這個實例的destroy方法。

          Servlet實例線程圖(如圖2)體現了這個生命周期模型。



          圖2 Servlet實例線程圖


          雖然可以讓所有的Servlet實現SingleThreadModel接口,但這會嚴重影響程序的性能。要解決多線程的同步問題,我們首先要分析共享對象的訪問模式。在一個Web程序中,共享對象按訪問模式可以分為以下兩類:一次設置、多次讀取的共享對象和多次設置、多次讀取的共享對象。

          一次設置、多次讀取

          對于這種共享對象,可以開發一個事件監聽器,監聽程序啟動和停止事件,代碼如下:

          
          package org.i18.listen
          import org.i18.utils.*;
          import javax.servlet.*;
          import util.Counter;
          public final class ContextListener implements ServletContextListener {
           private ServletContext context =null;
           public void contextInitialized(ServletContextEvent event){
            context =event.getServletContext();
            SynObject synObject = new SynObject();
            //在這里把共享對象放在應用對象中
            context.setAttribute("SYNOBJECT",synObject);
           }
           public void contextDestroyed(ServletContextEvent event){
            context =event.getServletContext();
            //清除保存在應用對象中的共享屬性
            context.removeAttribute("SYNOBJECT ");
           }
          }
          


          這樣,當Web應用程序啟動時,容器會調用監聽器,從而設置共享對象。共享對象的訪問只需直接調用getAttribute方法即可。

          多次設置、多次讀取

          對于多次設置、多次讀取的共享對象,必須利用Java的同步機制,訪問步驟如下:

          第一步,首先設計一個同步類。這個同步類的代碼非常簡單:

          
          package org.i18.utils
          public final class SynObject{
          }
          


          以上代碼可以看出,它其實什么都沒做,但繼承了Object關于同步的方法和機制。

          第二步,把這個類的實例放到應用對象中作為一個共享對象。可以看出這個同步對象屬于一次設置、多次使用的共享對象。在應用程序啟動事件監聽器中設置它,請參見前面的代碼。

          第三步,設置共享對象。如果有對象需要整個應用程序共享,可以在Servlet的service中利用同步機制來設置:

          
          public void doGet (HttpServletRequest request,HttpServletResponse response)
          throws ServletException,IOException {
           ServletContext context=   getServletContext();
           //得到同步對象
           Object obj = context.getAttribute("SYNOBJECT");  
           //獲取同步鑰匙
           synchronized(obj){
            //先檢查是否存在這個共享對象
            Object obj2 = context.getAttribute("Attr");
            if (obj2 == null) {
             //不存在,設置共享對象
             obj2 = new TestBean();
             context.setAttribute("Attr",obj2);
            }
           }
          }
          


          第四步,讀取共享對象。當需要訪問多次設置、多次訪問的共享對象時,同樣需要利用同步機制,代碼如下:

          
          public void doGet (HttpServletRequest request,HttpServletResponse response)
          throws ServletException,IOException {
           ServletContext context=   getServletContext();
           //得到同步對象,因為這個對象是一次設置、多次讀取型的,不需要同步
           Object obj = context.getAttribute("SYNOBJECT");  
           //獲取同步鑰匙
           synchronized(obj){
            //得到需要的共享對象
            Object obj2 = context.getAttribute("Attr");
           }
          }
          


          會話對象內共享對象的多線程問題可以和應用對象一樣處理。請求對象和頁面對象正常情況下是線程安全的,除非開發者自己引入了額外的線程。

          本文分析了開發好的J2EE應用必須掌握的、組件間對象共享的技術,這種分析技術同樣適用于EJB中。在EJB容器中,信息存放的位置變成了實現JNDI的服務提供者,大家通過JNDI的接口方法查詢、綁定共享對象。需要注意的是,同步對象不能在JNDI中實現,因為大家搜索出來的不是同一個內存對象。

          posted on 2005-04-08 14:41 笨笨 閱讀(614) 評論(0)  編輯  收藏 所屬分類: J2EE 、ALLStruts
          主站蜘蛛池模板: 梧州市| 巩义市| 石首市| 五大连池市| 吕梁市| 砚山县| 南郑县| 五指山市| 邛崃市| 南丹县| 梧州市| 饶河县| 新竹县| 清远市| 无锡市| 鄯善县| 虹口区| 宁强县| 乌兰浩特市| 建宁县| 波密县| 濉溪县| 资阳市| 祥云县| 西贡区| 武清区| 辽中县| 庆安县| 双峰县| 阳新县| 阿克苏市| 宜兴市| 突泉县| 石林| 任丘市| 绿春县| 左贡县| 河南省| 中阳县| 峨眉山市| 九江县|