xwork

ActionContext作爲xwork的數據流實現的元素,作爲一個數據載體,負責數據存儲,又負責數據共享。

ValueStack是一個具備表達式引擎計算功能的數據結構。xwork將ValueStack置於ActionContext中目的爲靜態的數據添加計算功能。


xwork的執行棧:

Interceptor與Action之間形成了包裹的結構。把Action包在最裏面,棧-----interceptor-stack,在整個站的結構中,除了位於棧底的Action外,其他元素都是Interceptor對象,當試圖吧Action對象拿出來時,要先把其之上的所有Interceptor依次拿出來執行,位於棧中的interceptor,除了需要她完成自身的邏輯外,還需要指定下一步的執行對象。

從源碼中,ActionContext真正的數據存儲空間,位於內部的一個Map類型的變量context,ActionContext將所有的數據對象以特定的鍵值存儲於context中,ActionContext頁提供了存取這些對象的方式。

數據共享:線程安全問題。

線程安全的判斷標準:進行數據共享的信息是類的內部實例變量,外部對內部數據的訪問是否存在多線程環境。ActionContext都滿足。。哈哈。

怎麼辦?源碼裏ActionContext內封裝了靜態的ThreadLocale的實例,而這靜態的ThreadLocale本身所操作和存儲的對象,又是ActionContext本身。所以保證ActionContext的實例都是線程安全的。使用ThreadLocale處理多線程問題,


ThreadLocal類在維護變量時,實際使用了當前線程(Thread)中的一個叫做ThreadLocalMap的獨立副本,每個線程可以獨立修改屬於自己的副本而不會互相影響,從而隔離了線程和線程,避免了線程訪問實例變量發生衝突的問題。

ThreadLocal本身並不是一個線程,而是通過操作當前線程(Thread)中的一個內部變量來達到與其他線程隔離的目的。之所以取名爲ThreadLocal,所期望表達的含義是其操作的對象是線程(Thread)的一個本地變量。如果我們看一下Thread的源碼實現,就會發現這一變量,如代碼清單4-2所示:

public class Thread implements Runnable {
 // 這裏省略了許多其他的代碼
ThreadLocal.ThreadLocalMap threadLocals = null;
}


這是JDK中Thread源碼的一部分,從中我們可以看出ThreadLocalMap跟隨着當前的線程而存在。不同的線程Thread,擁有不同的ThreadLocalMap的本地實例變量,這也就是“副本”的含義。接下來我們再來看看ThreadLocal.ThreadLocalMap是如何定義的,以及ThreadLocal如何來操作它,如代碼清單4-3所示:

public class ThreadLocal<T> {

// 這裏省略了許多其他代碼

// 將value的值保存於當前線程的本地變量中
public void set(T value) {
    // 獲取當前線程
    Thread t = Thread.currentThread();
    // 調用getMap方法獲得當前線程中的本地變量ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    // 如果ThreadLocalMap已存在,直接使用
    if (map != null)
         // 以當前的ThreadLocal的實例作爲key,存儲於當前線程的
         // ThreadLocalMap中,如果當前線程中被定義了多個不同的ThreadLocal
         // 的實例,則它們會作爲不同key進行存儲而不會互相干擾
         map.set(this, value);
    else
         // ThreadLocalMap不存在,則爲當前線程創建一個新的
         createMap(t, value);
}

 // 獲取當前線程中以當前ThreadLocal實例爲key的變量值
public T get() {
    // 獲取當前線程
    Thread t = Thread.currentThread();
    // 獲取當前線程中的ThreadLocalMap
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        // 獲取當前線程中以當前ThreadLocal實例爲key的變量值
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null)
            return (T)e.value;
    }
    // 當map不存在時,設置初始值
    return setInitialValue();
}

// 從當前線程中獲取與之對應的ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

 // 創建當前線程中的ThreadLocalMap
void createMap(Thread t, T firstValue) {
    // 調用構造函數生成當前線程中的ThreadLocalMap
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

// ThreadLoaclMap的定義
static class ThreadLocalMap {
    // 這裏省略了許多代碼
}
}


從上述代碼中,我們看到了ThreadLocal類的大致結構和進行ThreadLocalMap的操作。我們可以從中得出以下的結論:

1. ThreadLocalMap變量屬於線程(Thread)的內部屬性,不同的線程(Thread)擁有完全不同的ThreadLocalMap變量。

2. 線程(Thread)中的ThreadLocalMap變量的值是在ThreadLocal對象進行set或者get操作時創建的。

3. 在創建ThreadLocalMap之前,會首先檢查當前線程(Thread)中的ThreadLocalMap變量是否已經存在,如果不存在則創建一個;如果已經存在,則使用當前線程(Thread)已創建的ThreadLocalMap。

4. 使用當前線程(Thread)的ThreadLocalMap的關鍵在於使用當前的ThreadLocal的實例作爲key進行存儲。


ThreadLocal模式,至少從兩個方面完成了數據訪問隔離,有了橫向和縱向的兩種不同的隔離方式,ThreadLocal模式就能真正地做到線程安全:

縱向隔離 —— 線程(Thread)與線程(Thread)之間的數據訪問隔離。這一點由線程(Thread)的數據結構保證。因爲每個線程(Thread)在進行對象訪問時,訪問的都是各自線程自己的ThreadLocalMap。

橫向隔離 —— 同一個線程中,不同的ThreadLocal實例操作的對象之間的相互隔離。這一點由ThreadLocalMap在存儲時,採用當前ThreadLocal的實例作爲key來保證。

ThreadLocal模式並不是什麼高深的學問,它甚至從JDK1.2開始就存在於Java世界中。由此可見,我們掌握一種知識的最終目的是熟練而合理地運用它。
ThreadLocal模式解決的是同一線程中隸屬於不同開發層次的數據共享問題,而不是在不同的開發層次中進行數據傳遞。



Java代碼 
// 代碼清單1 SimpleThreadLocal  
class SimpleThreadLocal {  
    private MapvalueMap = Collections.synchronizedMap(new HashMap());  
    public voidset(Object newValue) {  
       valueMap.put(Thread.currentThread(), newValue);//①鍵爲線程對象,值爲本線程的變量副本  
    }  
    publicObject get() {  
       Thread currentThread = Thread.currentThread();  
       Object o = valueMap.get(currentThread);// ②返回本線程對應的變量  
       if (o == null &&!valueMap.containsKey(currentThread)) {// ③如果在Map中不存在,放到Map  
           // 中保存起來。  
           o = initialValue();  
           valueMap.put(currentThread, o);  
       }  
       return o;  
    }  
    public voidremove() {  
       valueMap.remove(Thread.currentThread());  
    }  
    publicObject initialValue() {  
       return null;  
    }  

兩種不同的接口訪問類型:

對xwork框架對象的訪問-----getContainer  getValueStack  getActionInvocation

對數據對象的訪問-----getSession、getApplication、getParameter

ActionContext所提供的數據對象的訪問接口,返回的是Map類型的數據對象而與web容器無關。


ActionContex是xwork框架所定義的元素,而xwork框架本身是脫離web容器而單獨存在的事件處理框架,因此ActionContext一旦引入web對象,勢必與xwork解耦合的基本設計思想背離。

web原生對象與xwork封裝後的對象的對應關係
web原生對象 xwork封裝後的對象
HttpServletRequest RequestMap
HttpSession SessionMap
ServletContext AppliactionMap
xwork 封裝過程的本質:被封裝後的SessionMap對象,能進一步保證數據訪問的線程安全性,保持所有存儲對象的Map結構,可以統一數據訪問格式。

可以通過調用ServletActionContext所暴露的接口完成對web原生容器的HttpServletRequest和HttpServletResponse的訪問。

發佈了36 篇原創文章 · 獲贊 11 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章