深入Struts2_數(shù)據(jù)流

1. 值棧

值棧是對應(yīng)每一個請求的輕量級的內(nèi)存數(shù)據(jù)中心,其實(shí)也是上一章講的數(shù)據(jù)流元素ActionContext與ValueStack.
從廣義上講,值棧就是ActionContext,它是action的上下文環(huán)境.而從狹義上講,值棧僅僅是指ValueStack.
ValueStack是ActionContext的一個組成部分.
數(shù)據(jù)流有兩個特性:數(shù)據(jù)和流.數(shù)據(jù)強(qiáng)調(diào)的是作為一個載體,流強(qiáng)調(diào)數(shù)據(jù)的訪問和傳輸.
ActionContext作為數(shù)據(jù)的載體,既負(fù)責(zé)數(shù)據(jù)的存儲也負(fù)責(zé)數(shù)據(jù)共享.
而ValueStack是一個具備表達(dá)式引擎計(jì)算能力的數(shù)據(jù)結(jié)構(gòu),是為了解決數(shù)據(jù)訪問和數(shù)據(jù)傳輸而定義得到特殊形象.
所以,Xwork將ValueStack置于ActionContext中的目的在于為靜態(tài)的數(shù)據(jù)添加動態(tài)計(jì)算的功能.

2. ActionContext

ActionContext是action的上下文環(huán)境.ActionContext真正的數(shù)據(jù)存儲空間,是Map類型的變量context.ActionContext將所有的數(shù)據(jù)對象都以特定的鍵值存儲與context之中.同時為了方便,提供了一些取值的快捷方式,如getValueStack,getSession.

  • 2.1 數(shù)據(jù)共享

在數(shù)據(jù)共享的時候,如何保證"線程安全"呢.

public class ActionContext implements Serializable {  
static ThreadLocal actionContext = new ThreadLocal();  
 ……  
 }

從源碼可以看出,在ActionContext內(nèi)部封裝了一個ThreadLocal實(shí)例,而ThreadLocal實(shí)例所操作和存儲的對象,又是ActionContext.這保證了其線程安全.

  • 2.2 數(shù)據(jù)存儲

ActionContext中存放了很多內(nèi)容(包括action自身),大致可以分為兩類:
對XWork框架對象的訪:getContainer,getValueStack,getActionInvocation等等..
對數(shù)據(jù)對象的訪問:getApplication,getSession,getParameters,getName等等..
值得注意的是,ActionContext對數(shù)據(jù)對象的訪問,得到的都是一個Map對象而不是類似HttpSession或者ServletContext這樣純正的Web容器對象.這主要還是因?yàn)?strong>Xwork與Web容器的解耦.
解耦之后可以對兩個方面做到更好:

  1. 被封裝后的SessionMap等對象,進(jìn)一步保證數(shù)據(jù)訪問的線程安全性.
  2. 保持所有存儲對象的Map結(jié)構(gòu),都有統(tǒng)一的數(shù)據(jù)訪問方式.

當(dāng)然我們還有更多存儲數(shù)據(jù)的方式.
使用xxxAware接口:可以使用類似SessionAware,RequestAware之類的接口通過使用IoC/DI來為Action注入Map.
使用ServletActionContext:這個類直接繼承了ActionContext,并且它能直接取到Servlet的相關(guān)對象,例如getRequest取到的就是HttpServletRequest.同時,使用這個子類同樣可以通過IOC/DI的方式注入,不過好像顯得多此一舉.

3. ValueStack

  • 3.1 OGNL

OGNL是對象圖導(dǎo)航語言O(shè)bject-Graph Navigation Language的縮寫,它是一種功能強(qiáng)大的表達(dá)式語言(Expression Language,簡稱為EL),通過它簡單一致的表達(dá)式語法,可以存取對象的屬性,調(diào)用對象的方法,遍歷整個對象的結(jié)構(gòu)圖,實(shí)現(xiàn)字段類型轉(zhuǎn)化等功能.它使用相同的表達(dá)式去存取對象的屬性.
所謂對象圖,即以任意一個對象為根,通過OGNL可以訪問與這個對象關(guān)聯(lián)的其它對象.

Emp emp=new Emp();
DepartMent department=new DepartMent();
Enterprise enterprise=new Enterprise();
enterprise.setName("A");
department.setEnterPrise(enterprise);
emp.setDepartment(department);

那么利用OGNL導(dǎo)航就可以是

  String value=(String)Ognl.getValue("department.enterprise.name",emp);

第一個參數(shù)是OGNL表達(dá)式,而第二個參數(shù)則是root對象.
由于OGNL中不支持多個root對象,所以如果要訪問多個不相干的對象,就需要一個context上下文對象,它是一個Map類型的對象.

Emp emp=new Emp();
emp.setName("張三");
Emp emp2=new Emp();
emp2.setName("李四");
Emp emp3=new Emp();
emp3.setName("王五");

Map context=new HashMap();
context.put("e1",emp);
context.put("e2",emp2);

String value=(String)Ognl.getValue("#e1.name+','+#e2.name+','+name",context,emp3);

這里把emp1和emp2存儲到map中,取值時候需要加#,而放在root中的emp3則可以直接取值.
OGNL還可以訪問數(shù)組與集合,如果數(shù)組與集合在context中,那么類似如下取值

 Ognl.getValue("#list[0]",context,root);
 Ognl.getValue("#array[0]",context,root);
 Ognl.getValue("#map['key']",context,root);
 Ognl.getValue("#map.key",context,root);

如果是存放在root中的,那么就類似#root[0].value
以上方式可以組合使用.放到Struts2中考慮一些復(fù)雜的例子:

  • 要獲取Session中一個key值為“users”的List,對應(yīng)的OGNL應(yīng)為#session[‘users’],或者#session.users
  • 要操作這個List的第3個元素,對應(yīng)的OGNL應(yīng)為#session[‘users’][2],或者#session.users[2]
  • 要操作這個對象的userId屬性,對應(yīng)的OGNL應(yīng)為#session[‘users’][2].userId,或者#session.users[2].userId

另外OGNL還可以進(jìn)行賦值操作,直接獲取root對象的方法,或者用@符號獲取靜態(tài)變量和方法等等,更多的知識可以去http://www.ognl.org.

  • 3.2 ValueStack

valuestack是對OGNL的一個擴(kuò)展.我們知道OGNL有三要素,表達(dá)式,context對象以及root對象.而valuestack的擴(kuò)展是針對root對象的.主要是,valuestack可以將一組對象都視為root對象,而在原生ognl中,root對象只有一個.
valuestack從抽象層面上講是一個棧,后入先出的鏈表結(jié)構(gòu).而valuestack實(shí)際上是一個接口,OgnlValueStack是其實(shí)現(xiàn)類.
觀察源碼可知,OgnlValueStack起核心作用的是一個叫CompoudRoot的數(shù)據(jù)結(jié)構(gòu),而它繼承于ArrayList.
知道了ValueStack的數(shù)據(jù)結(jié)構(gòu)后,來看看其對OGNL計(jì)算規(guī)則的影響.
由于可以有多個root對象(包括action本身),在進(jìn)行表達(dá)式匹配的時候,從棧的頂端開始自上而下對每個棧內(nèi)元素進(jìn)行遍歷匹配計(jì)算 .返回第一個成功匹配的結(jié)果.
另外,有兩個重要的概念:棧頂元素和子棧.
所謂棧頂元素,就是可以通過[0]進(jìn)行訪問的元素,同時也可以通過top進(jìn)行訪問.
而子棧,就是出去棧頂元素以外的棧結(jié)構(gòu).[n]表示除去棧結(jié)構(gòu)中前n個元素之后所構(gòu)成的棧.
一個大小為N的ValueStack,除了自身,有N-1個子棧
每一個子棧自身也是一個ValueStack,構(gòu)成遞歸的數(shù)據(jù)結(jié)構(gòu)
顯然我們可以用top訪問第一個元素,用[1].top訪問第二個元素.

4. 水乳交融的ActionContext與ValueStack

水乳交融用來描述兩者之間的關(guān)系.在學(xué)習(xí)的時候,這種密切會帶來一些困擾,至少我之前是的.
ActionContext的創(chuàng)建,總是伴隨著ValueStack的創(chuàng)建
緊接著ValueStack的創(chuàng)建就是ActionContext的創(chuàng)建,而ActionContext的創(chuàng)建以ValueStack的上下文環(huán)境作為參數(shù).兩者幾乎是相同時刻創(chuàng)建出來的.
ValueStack的上下文環(huán)境與ActionContext的數(shù)據(jù)存儲空間一致
意味著
ValueStack.getContext()==ActionContext.getContext().getContextMap()
說明兩者可以互相得到.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產(chǎn)品,是在 struts1和WebWork的...
    inke閱讀 2,343評論 0 50
  • 本文包括:1、OGNL 表達(dá)式概述(了解)2、值棧概述3、值棧的存值與取值4、EL 表達(dá)式也會獲取到值棧中的數(shù)據(jù)5...
    廖少少閱讀 1,314評論 0 14
  • action中如何接受頁面?zhèn)鬟^來的參數(shù) 第一種情況:(同名參數(shù)) 例如:通過頁面要把id=1 name=tom a...
    清楓_小天閱讀 3,286評論 1 22
  • 非本人總結(jié)的筆記,抄點(diǎn)筆記復(fù)習(xí)復(fù)習(xí)。感謝傳智博客和黑馬程序猿記筆記啊記筆記 Ognl的簡介 Ognl是獨(dú)立的項(xiàng)目,...
    鍵盤瞎閱讀 636評論 0 2
  • 來廈門已經(jīng)8天,恰巧趕上了清明時節(jié)的紛紛雨,前天晚上開始,或一時細(xì)雨霏霏,忽而雨點(diǎn)敲擊著房屋外的遮擋版,在獨(dú)自一人...
    謝方閱讀 306評論 0 0

友情鏈接更多精彩內(nèi)容