1:在action中定義的變量,在jsp頁面中顯示用:<s:property value="變量名" />
2:在頁面中實現自動增加的序號用iterator的statuts的index屬性 eg:
<s:iterator value="#request.inOutAccountList" id="data" status="listStat">
<s:property value="#listStat.index+1"/>
</s:iterator>
3:在action類中取得request和session對象的方法
Map session = ActionContext.getContext().getSession();
HttpServletRequest request = ServletActionContext.getRequest ();
設置它們的值的方法
session.put("operation", "add");
request.setAttribute("name", name);
頁面中取得它們的值:
<s:property value="#session.operation"/>
<s:property value="#request.name"/>
4:頁面中奇偶行樣式不一樣的控制方法:
<tr class="<s:if test='#listStat.odd == true '>tableStyle-tr1</s:if><s:else>tableStyle-tr2</s:else>" >
5:單選框和復選框的使用方法
1):可以設置默認選中值,注意list的值的設置,通過這種方式使key和value不一樣,這種方法比較常用(checkboxlist or radio)
<s:radio name="uncarInsPolicy.policyStateCode"
list="#{'5':'通過' , '2':'不通過'}"
listKey="key"
listValue="value"
value='5'
/>
2):這里的key和value的值是一樣的(checkboxlist or radio)
<s:checkboxlist
list="{'Red', 'Blue', 'Green'}"
name="favoriteColor"/>
6:struts2 中的標簽會生成類似由<tr><td></td></tr>構成的字串(具體什么標簽生成什么,可以查看生成后的頁面的源代碼)如果不限制這些多余代碼的生成,頁面將變得無法控制,所以一般我們是不希望它生成多余的代碼的,具體的設置方法如果,在struts.xml中統一配置
<constant name="struts.ui.theme" value="simple"/>加上該句即可
也可以通過在頁面中將tag的theme屬性設為"simple"取消其默認的表格布局
不過最好是:自定義一個theme,并將其設為默認應用到整個站點,如此一來就可以得到統一的站點風格
7:jsp頁面中格式化日期的方法
<s:date name="unCarInsModificationInfo.createTime" format="yyyy-MM-dd" nice="false"/>這樣就可以將日期格式化為yyyy-MM-dd的形式
8:默認情況下,當請求action發生時,Struts運行時(Runtime)根據struts.xml里的Action映射集(Mapping),實例化action對應的類,并調用其execute方法。當然,我們可以通過以下兩種方法改變這種默認調用
1)在classes/sturts.xml中新建Action,并指明其調用的方法
比如想調用action類中的
public String aliasAction() {
message ="自定義Action調用方法";
return SUCCESS;
}
則在classes/sturts.xml中加入下面代碼:
<action name="AliasHelloWorld" class="tutorial.HelloWorld" method="aliasAction">
<result>/HelloWorld.jsp</result>
</action>
既可用action名調用該方法了
2)(比較常用)
訪問Action時,在Action名后加上“!xxx”(xxx為方法名)。
9:Struts 2.0有兩個配置文件,struts.xml和struts.properties都是放在WEB-INF/classes/下。
struts.xml用于應用程序相關的配置
struts.properties用于Struts 2.0的運行時(Runtime)的配置
10:在action類中取得web下某一文件夾物理路徑(絕對路徑)的方法
filePath = ServletActionContext.getServletContext().getRealPath("/upLoadFiles")
11:要想返回的頁面不是一個直接JSP頁面而是要先通過返回action中的方法讀取相應的數據再返回到jsp頁面,有兩種方法
1)在struts.xml中這么設置
<result name="list" type="redirect-action">sysmanage/UserBaseInfoAction!findUserBaseInfo.action</result>
2)在action中返回時直接調用這個方法即可
return findList();
12:設置checkboxlist中默認值的方法
<s:checkboxlist name="skills1"
="Skills 1"
list="{ 'Java', '.Net', 'RoR', 'PHP' }"
value="{ 'Java', '.Net' }" />
<s:checkboxlist name="skills2"
label="Skills 2"
list="#{ 1:'Java', 2: '.Net', 3: 'RoR', 4: 'PHP' }"
listKey="key"
listValue="value"
value="{ 1, 2, 3 }"/>
13:二級級連下拉框
<s:set name="foobar"
value="#{'Java': {'Spring', 'Hibernate', 'Struts 2'}, '.Net': {'Linq', ' ASP.NET 2.0'}, 'Database': {'Oracle', 'SQL Server', 'DB2', 'MySQL'}}" />
<s:doubleselect list="#foobar.keySet()"
doubleName="technology"
doubleList="#foobar[top]"
label="Technology" />
在Struts1.*中,要想訪問request、response以及session等Servlet對象是很方便的,因為它們一直是作為形參在各個方法之間進行傳遞的,而在Struts2中我們就很難看到它們的芳蹤了,因為我們獲得表單中的值都是通過預先設置好了的get方法來得到的,那么如果有些參數我們必須通過request.getParametre或者session.getAttribute來得到,那么應該怎么做呢?按照Max的教程上的說法,可以分為兩種:IoC方式和非IoC方式,如何理解這兩種方式的區別呢?IoC是Spring里面的特征之一,字面意思是反轉控制,說白了就是依賴注入,比方說類A依賴類B,那么就主動的給A注入一個類B的對象,下面看一下這兩種方法的具體實現。
1.非Ioc方式
這種方式主要是利用了 com.opensymphony.xwork2.ActionContext 類以及 org.apache.struts2.ServletActionContext 類,具體的方法如下所示。
獲得request對象:
A.HttpServletRequest request = ServletActionContext.getRequest ();
B.ActionContext ct= ActionContext. getContext ()
?? HttpServletRequest request=
(HttpServletRequest)ct.get(ServletActionContext. HTTP_REQUEST );
獲得session對象:
在Struts2中底層的session都被封裝成了Map類型,我們稱之為SessionMap,而平常我們所說的session則是指HttpSession對象,具體的獲得方法如下所示。
A.Map session=ActionContext.getSession();
B.Map session=(Map)ActionContext.getContext().get(ActionContext.SESSION);
得到這個SessionMap之后我們就可以對session進行讀寫了,如果我們想得到原始的 HttpSession 可以首先得到 HttpServletRequest 對象,然后通過 request.getSession() 來取得原始的 HttpSession 對象。一般情況下SessionMap已經可以完成所有的工作,我們不必再去碰底層的session了。
2.IoC方式
這種方式相對來說變化就比較少了,具體流程如下所示。
獲得request對象:
第一步:讓 action 實現 ServletRequestAware 接口
第二步:在 action 中聲明一個 HttpServletRequest 類型的實例變量
第三步:在 action 中實現 ServletRequestAware 接口的 setServletRequest 方法,實現方式很簡單,如下所示。
???????? private HttpServletRequest request;
publicvoid setServletRequest (HttpServletRequest request) {
??????? ???? this .request = request;
??? }
獲得Session對象(注意,此時的session是SessionMap類型):
第一步:讓 action 實現 SessionAware 接口
第二步:在 action 中聲明一個 HttpServletRequest 類型的實例變量
第三步:在 action 中實現 SessionAware 接口的 setSession 方法,實現方式很簡單,如下所示。
?
?
設計模式(Design pattern)是經過程序員反復實踐后形成的一套代碼設計經驗的總結。設計模式隨著編程語言的發展,也由最初的“編程慣例”逐步發展成為被反復使用、并為絕大多數程序員所知曉的、完善的理論體系。我們使用設計模式(Design pattern)的初衷,是使代碼的重用度提高、讓代碼能夠更容易被別人理解以及保證代碼的可靠性。毫無疑問,在程序中使用設計模式無論是對于程序員自身還是對于應用程序都是雙贏的結果。正確地使用設計模式,能夠使我們編程真正實現工程化和規范化,并且在一定程度上指導著框架的設計和實現。
在深入探討Struts2所依賴的核心技術之前,我們將首先帶領讀者領略一下在整個Struts2框架之中所使用到的一些最常用的設計模式。理解這些設計模式的運用場景和內部機理,也將為日后我們對這些核心技術的分析打下堅實的基礎。
4.1 ThreadLocal模式
ThreadLocal模式,嚴格意義上來說并不能稱之為一種設計模式,因為它只是一個用來解決多線程程序中數據共享問題的一個解決方案。盡管如此,ThreadLocal模式卻貫穿了整個Struts2和XWork框架,成為Struts2框架進行“解耦”設計的核心依賴技術。那么,為什么要在Struts2中引入ThreadLocal模式呢?這不得不從Web開發中的線程安全問題談起。
4.1.1線程安全問題的由來
在傳統的Web開發中,我們處理Http請求最常用的方式是通過實現Servlet對象來進行Http請求的響應。Servlet是J2EE的重要標準之一,規定了Java如何響應Http請求的規范。通過HttpServletRequest和HttpServletResponse對象,我們能夠輕松地與Web容器交互。
當Web容器收到一個Http請求時,Web容器中的一個主調度線程會從事先定義好的線程池中分配一個當前工作線程,將請求分配給當前的工作線程,由該線程來執行對應的Servlet對象中的service方法。如果這個工作線程正在執行的時候,Web容器收到另外一個請求,主調度線程會同樣從線程池中選擇另一個工作線程來服務新的請求。Web容器本身并不關心這個新的請求是否訪問的是同一個Servlet實例。因此,我們可以得出一個結論:
對于同一個Servlet對象的多個請求,Servlet的service方法將在一個多線程的環境中并發執行。
所以,Web容器默認采用
單實例(單Servlet實例)多線程
的方式來處理Http請求。這種處理方式能夠減少新建Servlet實例的開銷,從而縮短了對Http請求的響應時間。但是,這樣的處理方式會導致變量訪問的線程安全問題。也就是說,Servlet對象并不是一個線程安全的對象。下面的測試代碼將證實這一點:
public class ThreadSafeTestServlet ex tends HttpServlet { // 定義一個實例變量,并非一個線程安全的變量 private int counter = 0; public vo id doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 輸出當前Servlet的信息以及當前線程的信息 System.out.print ln (this + ":" + Thread.currentThread()); // 循環,并增加實例變量counter的值 for (int i = 0; i < 5; i++) { System.out.println("Counter = " + counter); try { Thread. sleep ((long) Math.random() * 1000); counter++; } cat ch (InterruptedException exc) { } } } }
這里參閱了網絡上一段著名的對Servlet線程安全性進行測試的代碼(http://z
wc
hen.iteye.com/blog/91088)。運行之后,我們可以看一下這個例子的輸出:
sample.SimpleServlet@11e1bbf:Thread[http-8081-Processor23,5,main] Counter = 60 Counter = 61 Counter = 62 Counter = 65 Counter = 68 Counter = 71 Counter = 74 Counter = 77 Counter = 80 Counter = 83 sample.SimpleServlet@11e1bbf:Thread[http-8081-Processor22,5,main] Counter = 61 Counter = 63 Counter = 66 Counter = 69 Counter = 72 Counter = 75 Counter = 78 Counter = 81 Counter = 84 Counter = 87 sample.SimpleServlet@11e1bbf:Thread[http-8081-Processor24,5,main] Counter = 61 Counter = 64 Counter = 67 Counter = 70 Counter = 73 Counter = 76 Counter = 79 Counter = 82 Counter = 85 Counter = 88
通過上面的輸出,我們可以得出以下三個Servlet對象的運行特性:
1. Servlet對象是一個無狀態的單例對象(Singleton),因為我們看到多次請求的this指針所打印出來的hashcode值都相同
2. Servlet在不同的線程(線程池)中運行,如http-8081-Processor22和http-8081-Processor23等輸出值可以明顯區分出不同的線程執行了同一段Servlet邏輯代碼。
3. Counter變量在不同的線程中共享,而且它的值被不同的線程修改,輸出時已經不是順序輸出。也就是說,其他的線程會篡改當前線程中實例變量的值,針對這些對象的訪問不是線程安全的。
【有關線程安全的概念范疇】
談到線程安全,對于許多初學者來說很容易引起概念上的混淆。線程安全,指的是在多線程環境下,一個類在執行某個方法時,
對類的內部實例變量的訪問安全與否。
因此,對于下面列出來的2類變量,不存在任何線程安全的說法:
1)方法簽名中的任何參數變量。
2)處于方法內部的局部變量。
任何針對上述形式的變量的訪問都是線程安全的,因為它們都處于方法體的內部,由當前的執行線程獨自管理。
這就是線程安全問題的由來:
在傳統的基于Servlet的開發模式中,Servlet對象內部的實例變量不是線程安全的。
在多線程環境中,這些變量的訪問需要通過特殊的手段進行訪問控制。
解決線程安全訪問的方法很多,比較容易想到的一種方案是使用同步機制,但是出于對Web應用效率的考慮,這種機制在Web開發中的可行性很低,也違背了Servlet的設計初衷。因此,我們需要另辟蹊徑來解決這一困擾我們的問題。
4.1.2 ThreadLocal模式的實現機理
在JDK的早期版本中,提供了一種解決多線程并發問題的方案: java.lang.ThreadLocal類。ThreadLocal類在維護變量時,實際使用了當前線程(Thread)中的一個叫做ThreadLocalMap的獨立副本,每個線程可以獨立修改屬于自己的副本而不會互相影響,從而隔離了線程和線程,避免了線程訪問實例變量發生沖突的問題。
ThreadLocal本身并不是一個線程,而是通過操作當前線程(Thread)中的一個內部變量來達到與其他線程隔離的目的。之所以取名為ThreadLocal,所期望表達的含義是其操作的對象是線程(Thread)的一個本地變量。如果我們看一下Thread的源碼實現,就會發現這一變量,如代碼清單4-2所示:
public class Thread implements Runnable { // 這里省略了許多其他的代碼 ThreadLocal.ThreadLocalMap threadLoca ls = 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的定義 stat ic 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模式與sy
nc
hronized關鍵字】
ThreadLocal模式與
sync
hronized關鍵字都是用于處理多線程并發訪問變量的問題。只是兩者處理問題的角度和思路不同。
1)ThreadLocal是一個Java類,通過對當前線程(Thread)中的局部變量的操作來解決不同線程的變量訪問的沖突問題。所以,ThreadLocal提供了線程安全的共享對象機制,每個線程(Thread)都擁有其副本。
2)Java中的synchronized是一個保留字,它依靠JVM的鎖機制來實現臨界區的函數或者變量在訪問中的原子性。在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。此時,被用作“鎖機制”的變量是多個線程共享的。
同步機制采用了“
以時間換空間
”的方式,提供一份變量,讓不同的線程排隊訪問。而ThreadLocal采用了“
以空間換時間
”的方式,為每一個線程都提供了一份變量的副本,從而實現同時訪問而互不影響。
4.1.3 ThreadLocal模式的應用場景
在分析了ThreadLocal的源碼之后,我們來看看ThreadLocal模式最合適的業務場景。在一個完整的“請求-響應”過程中,主線程的執行過程總是貫穿始終。當這個主線程的執行過程中被加入了ThreadLocal的讀寫時,會對整個過程產生怎樣的影響呢?我們根據之前源碼分析的結果,并結合分層開發模式,把整個流程畫下來,如圖4-1所示:
從上面圖中我們可以看到,由于ThreadLocal所操作的是維持于整個Thread生命周期的副本(ThreadLocalMap),所以無論在J2EE程序程序的哪個層次(表示層、業務邏輯層或者持久層),只要在一個Thread的生命周期之內,存儲于ThreadLocalMap中的對象都是線程安全的(因為ThreadLocalMap本身僅僅隸屬于當前的執行線程,是執行線程內部的一個屬性變量。我們用圖中的陰影部分來表示這個變量的存儲空間)。而這一點,正是被我們用于來解決多線程環境中的變量共享問題的核心技術。ThreadLocal的這一特性也使其能夠被廣泛地應用于J2EE開發中的許多業務場景。
【數據共享 OR 數據傳遞?】
ThreadLocal模式由于利用了Java自身的語法特性而顯得異常簡單和便利,因而被廣泛應用于J2EE開發,尤其是應對跨層次的資源共享,例如在Spring中,就有使用ThreadLocal模式來管理數據庫連接或者Hibernate的Session的范例。
在一些比較著名的
論壇
中,有著很多關于使用ThreadLocal模式來做數據傳遞的討論。事實上,這是對ThreadLocal模式的一個極大的誤解。讀者需要注意的是,
ThreadLocal模式解決的是同一線程中隸屬于不同開發層次的數據共享問題,而不是在不同的開發層次中進行數據傳遞。
1)ThreadLocal模式的核心在于實現一個共享環境(類的內部封裝了ThreadLocal的靜態實例)。所以,在操作ThreadLocal時,這一共享環境會跨越多個開發層次而隨處存在。
2)隨處存在的共享環境造成了所有的開發層次的共同依賴,從而使得所有的開發層次都耦合在了一起,從而變得無法獨立測試。
3)數據傳遞應該通過接口函數的簽名顯式聲明,這樣才能夠從接口聲明中表達接口所表達的真正含義。ThreadLocal模式位于實現的內部,從而使得接口與接口之間無法達成一致的聲明契約。
Struts2的解耦合的設計理念使得Struts2的MVC實現成為了使用ThreadLocal模式的天然場所。在第三章中,我們已經介紹了一些基本概念,Struts2通過引入XWork框架,將整個Http請求的過程拆分成為與Web容器有關和與Web容器無關的兩個執行階段。而這兩個階段的數據交互就是通過ThreadLocal模式中的線程共享副本安全地進行。在其中,我們沒有看到數據傳遞,存在的只是整個執行線程的數據共享。
4.1.4 ThreadLocal模式的核心元素
仔細分析上一節的示意圖(圖4-1),我們可以發現,要完成ThreadLocal模式,其中最關鍵的地方就是
創建一個任何地方都可以訪問到的ThreadLocal實例(也就是執行示意圖中的菱形部分)。
而這一點,我們可以通過類的靜態實例變量來實現,這個用于承載靜態實例變量的類就被視作是一個共享環境。我們來看一個例子,如代碼清單4-4所示:
public class Counter { // 新建一個靜態的ThreadLocal變量,并通過get方法將其變為一個可訪問的對象 private static ThreadLocal<Integer> counterContext = new ThreadLocal<Integer>() { protected synchronized Integer initialValue() { return 10; } }; // 通過靜態的get方法訪問ThreadLocal中存儲的值 public static Integer get() { return counterContext.get(); } // 通過靜態的set方法將變量值設置到ThreadLocal中 public static void set(Integer value) { counterContext.set(value); } // 封裝業務邏輯,操作存儲于ThreadLocal中的變量 public static Integer getNextCounter() { counterContext.set(counterContext.get() + 1); return counterContext.get(); } }
在這個Counter類中,我們實現了一個靜態的ThreadLocal變量,并通過get方法將ThreadLocal中存儲的值暴露出來。我們還封裝了一個帶有業務邏輯的方法getNextCounter,操作ThreadLocal中的值,將其加1,并返回計算后的值。
此時,Counter類就變成了一個數據共享環境,我們也擁有了實現ThreadLocal模式的關鍵要素。有了它,我們來編寫一個簡單的測試,如代碼清單4-5所示:
public class ThreadLocalTest extends Thread { public void run() { for(int i = 0; i < 3; i++){ System.out.println("Thread[" + Thread.currentThread().getName() + "],counter=" + Counter.getNextCounter()); } } }
這是一個簡單的線程類,循環輸出當前線程的名稱和getNextCounter的結果,由于getNextCounter中的邏輯所操作的是ThreadLocal中的變量,所以無論同時有多少個線程在運行,返回的值將僅與當前線程的變量值有關,也就是說,在同一個線程中,變量值會被連續累加。這一點可以通過如下的測試代碼證實:
public class Test { public static void main(String[] args) throws Exception { ThreadLocalTest testThread1 = new ThreadLocalTest(); ThreadLocalTest testThread2 = new ThreadLocalTest(); ThreadLocalTest testThread3 = new ThreadLocalTest(); testThread1.start(); testThread2.start(); testThread3.start(); } }
我們來運行一下上面的代碼,并看看輸出結果:
Thread[Thread-2],counter=11 Thread[Thread-2],counter=12 Thread[Thread-2],counter=13 Thread[Thread-0],counter=11 Thread[Thread-0],counter=12 Thread[Thread-0],counter=13 Thread[Thread-1],counter=11 Thread[Thread-1],counter=12 Thread[Thread-1],counter=13
上面的輸出結果也證實了,counter的值在多線程環境中的訪問是線程安全的。從對例子的分析中我們可以再次體會到,ThreadLocal模式最合適的使用場景:
在同一個線程(Thread)的不同開發層次中共享數據。
從上面的例子中,我們可以簡單總結出實現ThreadLocal模式的兩個主要步驟:
1. 建立一個類,并在其中封裝一個靜態的ThreadLocal變量,使其成為一個共享數據環境。
2. 在類中實現訪問靜態ThreadLocal變量的靜態方法(設值和取值)。
建立在ThreadLocal模式的實現步驟之上,ThreadLocal的使用則更加簡單。在線程執行的任何地方,我們都可以通過訪問共享數據類中所提供的ThreadLocal變量的設值和取值方法安全地獲得當前線程中安全的變量值。
這兩個步驟,我們之后會在Struts2的實現中多次提及,讀者只要能充分理解ThreadLocal處理多線程訪問的基本原理,就能對Struts2的數據訪問和數據共享的設計有一個整體的認識。
講到這里,我們回過頭來看看ThreadLocal模式的引入,到底對我們的編程模型有什么重要的意義呢?
downpour 寫道
結論
?使用ThreadLocal模式,可以使得數據在不同的編程層次得到有效地共享。
這一點,是由ThreadLocal模式的實現機理決定的。因為實現ThreadLocal模式的一個重要步驟,就是構建一個靜態的共享存儲空間。從而使得任何對象在任何時刻都可以安全地對數據進行訪問。
downpour 寫道
結論
?使用ThreadLocal模式,可以對執行邏輯與執行數據進行有效解耦。
這一點是ThreadLocal模式給我們帶來的最為核心的一個影響。因為在一般情況下,Java對象之間的協作關系,主要通過參數和返回值來進行消息傳遞,這也是對象協作之間的一個重要依賴。而ThreadLocal模式徹底打破了這種依賴關系,通過線程安全的共享對象來進行數據共享,可以有效避免在編程層次之間形成數據依賴。這也成為了XWork事件處理體系設計的核心。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
