1. 程式人生 > >struts2--關於值棧的概念性問題

struts2--關於值棧的概念性問題

結論:

1 狹義值棧

通常指的是實現com.opensymphony.xwork2.util.ValueStack介面的物件,目前就是com.opensymphony.xwork2.ognl.OgnlValueStack物件。

  狹義值棧主要用來存取動態EL(表示式語言)運算需要的值和結果,當然OgnlValueStack物件主要是用來支援OGNL(物件圖導航語言)運算的。狹義值棧裡面存放著一些OGNL可以存取訪問的資料,典型如:

  • Action的例項,這樣就可以通過OGNL來訪問Action例項中的屬性的值了
  • OGNL表示式運算的值,可以設定到值棧中,可以主動訪問值棧物件,強行設定
  • OGNL表示式產生的中間變數,比如在後面使用Struts2的標籤的時候,使用迴圈標籤,自然會有迴圈的變數,這些都存放在值棧中
2廣義值棧

最大的值棧為廣義值棧,通常指的是ActionContext物件,ActionContext是Action執行的上下文,每個ActionContext是一個基本的容器,包含著Action執行需要的資料,比如請求引數、會話等。

  ActionContext是執行緒安全的,每個執行緒有一個獨立的ActionContext,這樣你就不用擔心值棧中值的執行緒安全問題了。ActionContext裡面存放有很多的值,典型如:

  • Request的parameters:請求中的引數,要注意這裡的資料是從請求物件裡面拷貝出來的,因此這裡資料的變化是不會影響到請求物件裡面的引數的值的
  • Request的Attribute:請求中的屬性,這裡其實就是個Map,存放著請求物件的屬性資料,這些資料和請求物件的Attribute是連動的
  • Session的Attribute:會話中的屬性,這裡其實就是個Map,存放著會話物件的屬性資料,這些資料和會話物件的Attribute是連動的
  • Application的Attribute:應用中的屬性,這裡其實就是個Map,存放著應用物件的屬性資料,這些資料和應用物件的Attribute是連動的
  • Value stack:也就是狹義值棧,ActionContext以value stack作為被OGNL訪問的根,簡單點說,OGNL在沒有特別指明的情況下,訪問的就是value stack裡面的資料
  • attr:在所有的屬性範圍中獲取值,依次搜尋page、request、session和application。

  我們知道Xwork與Web是無關的,因此Action不用去依賴於任何Web容器,不用和Servlet 的API去互動,但是Action需要能訪問到Web應用的資料,不僅僅是取得請求引數的值,往往也需要在Action裡直接獲取請求或會話的一些資料,對於這些資料,現在都可以通過ActionContext來獲取到。

關於廣義值棧和狹義值棧

你會看到,在ActionContext裡面其實是包含著狹義值棧的,正是因為這個原因,再加上ActionContext還包含其他的資料,因此把ActionContext稱為廣義值棧。今後在說值棧的時候,沒有特別指明的情況下,多數就是指的廣義值棧,反正開發的時候都是說從值棧中獲取值。當然,有一種情況除外,就是在頁面上使用OGNL的時候,沒有特殊標識的情況下,預設是從value statck中取值的。

值棧其實就是記憶體分析,在Struts2中就叫根物件和棧文字,類似於JAVA中對變數和物件的記憶體分析
值棧ValueStack是Struts2框架核心元件,它提供對上下文資訊和執行環境中元 素的訪問機制。其在底層實現了一個棧 值棧由以下4個層級物件組成 (1)臨時物件:這些物件在請求處理過程中需要臨時儲存,比如集合中當前正在迭代的元素; (2) (2) 模型物件:當Action實現了ModelDriven介面時,模型物件就會被存放在棧中被執行的Action前面;否則不存在這個級別的內容。 (3) Action物件:此物件為當前正在執行的action。 (4) 命名物件:任何物件都可以被賦予一個標誌符而成為命名物件。比如與HTTP同等作用域的物件集合對應的Struts2命名物件,#application、#session、#request、#attr和#parameters等。
當struts2框架接收到一個HTTP請求時,它立刻建立一個ActionContext、ValueStack、Action物件 , 然後把action物件存放進ValueStack 中,再通過ActionContext 物件訪問ValueStack 中的資訊,而這個訪問的過程就是OGNL表示式訪問操作

值棧中分為root根物件和棧文字,值棧中主要存放Action物件,棧文本里主要是一些Map對映parameters、request、session、application、attr
Ø在action中訪問值棧 每個請求都建立一個與相應Action對應的ActionContext作為OGNL的上下文環境和ValueStack,並且把Action裡面的屬性值壓入ValueStack,這時的屬性值都是初始化值 從ActionContext 中獲取上下文物件 ActionContext actionContext=ActionContext.getContext(); 再從上下文物件中獲取值棧 ValueStack valueStack=actionContext.getValueStack();
Ø操作根物件中的資料 從值棧中獲取指定位置的根物件 valueStack.getRoot().get(0); 這個物件可以是當前的action物件,然後就可以操作當前物件中的資料了 它還提供了更加方便的取值方法,直接就從根物件中取值 valueStack.findValue(“…"); 給根物件中的屬性設定值,如果屬性名稱一樣,會覆蓋之前的屬性值 valueStack.setValue(“…");//要求action中有set方法,即給屬性重新賦值 valueStack.set(“…”);//隨意一個屬性名稱,在根物件中會生成一個HashMap,(在後臺除錯中可以看到),不需要set方法,就是一個獨立的屬性(最新版本一樣) 還可以往值棧中壓物件,把物件壓力棧頂 valueStack.getRoot().push(“…");
Ø操作棧文字中的資料 因為棧文字中主要存放parameters、request、session、application、attr的Map對映,以便在頁面上直接可以訪問。其實這個棧文字就是為了封裝servlet中的request、session等物件,實現鬆耦合,以後對request等物件的引數或屬性的操作就可以用requestMap的屬性操作 獲取requestMap requestMap=(Map)ActionContext.getContext().get("request"); 然後通過requestMap的key(引數或者屬性) requestMap.get(“key”),就能獲取引數或者屬性的值了 因為當一個請求過來,ActionContext就能接受所有的請求引數,並且存放在ActionContext 棧文字中,可以獲取對應的棧文字或者對其進行修改 給requestMap賦值,其實底層就是在給request物件賦值 (Map)ActionContext.getContext().get("request"). put(“”,””);
Ø在頁面中訪問值棧 在Struts2頁面中操作值棧,OGNL表示式需要配合Struts標籤才可以使用 如:<s:property value="name"/> 為了方便在頁面端測試,開啟<s:debug></s:debug>標籤
一個OGNL表示式,必須選擇ActionContext中的一個物件作為根物件(root),預設情況下,是選擇valueStack作為根物件,如果需要使用另外5個物件作為根物件,需要加上#字首 

簡練總結:

廣義值棧包括臨時變數、狹義值棧(value stack,預設狹義value stack為根物件,是一個意思,尤其在OGNL表示式中),還有application session request attr parameters(都在棧文字中) 這三類,重要的是在狹義值棧中,也就是預設的根物件中(可以指定棧文字為根物件),這裡主要存放著action物件,以及action物件的一些屬性變數(可以直接通過狹義值棧跳過根目錄直接對根目錄中的變數取值)

獲得上下文物件(廣義值棧)

ActionContext.getContext();

獲得狹義值棧的方法

ActionContext.getContext().getValueStack();

獲得狹義值棧中的根物件的方法(預設狹義值棧中的為根物件) ActionContext.getContext().getValueStack().getRoot();
獲取指定位置的根物件 ActionContext.getContext().getValueStack().getRoot().get(0);
直接通過狹義值棧跳過根目錄直接對根目錄中的變數取值
ActionContext.getContext().getValueStack().findValue(“…"); 給根物件中的屬性設定值,如果屬性名稱一樣,會覆蓋之前的屬性值 valueStack.setValue(“…");//要求action中有set方法,即給屬性重新賦值 valueStack.set(“…”);//隨意一個屬性名稱,在根物件中會生成一個HashMap,(在後臺除錯中可以看到),不需要set方法,就是一個獨立的屬性(最新版本一樣) 還可以往值棧中壓物件,把物件壓力棧頂 valueStack.getRoot().push(“…");