------------------------------------------------------------------------------
線程安全概念
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變量的值也和預期的是一樣的,就是線程安全的。
或者說:一個類或者程序所提供的接口對於線程來說是原子操作或者多個線程之間的切換不會導致該接口的執行結果存在二義性,也就是說我們不用考慮同步的問題。
線程安全問題都是由全局變量及靜態變量引起的。
若每個線程中對全局變量、靜態變量只有讀操作,而無寫操作,一般來說,這個全局變量是線程安全的;若有多個線程同時執行寫操作,一般都需要考慮線程同步,否則就可能影響線程安全。
----------------------------------------------------------------------------------------------------------
3.4 Action類
Action類真正實現應用程序的事務邏輯,它們負責處理請求。在收到請求後,ActionServlet會:
爲這個請求選擇適當的Action,如果需要,創建Action的一個實例,調用Action的perform()方法,如果ActionServlet不能找到有效的映射,它會調用默認的Action類(在配置文件中定義)。如果找到了ActionServlet將適當的ActionMapping類轉發給Action,這個Action使用ActionMapping找到本地轉發,然後獲得並設置ActionMapping屬性。根據servlet的環境和被覆蓋的perform()方法的簽名,ActionServlet也會傳送ServletRequest對象或HttpServletRequest對象。
所有Action類都擴展org.apache.struts.action.Action類,並且覆蓋類中定義的某一個perform()方法。有兩個perform()方法:
處理非HTTP(一般的)請求:
public ActionForward perform(ActionMapping action,
AcionForm form,
ServletRequest request,
ServletResponse response)
throws IOException,ServletException
處理HTTP請求:
public ActionForward perform(ActionMapping action,
AcionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException,ServletException
Action類必須以“線程安全”的方式進行編程,因爲控制器會令多個同時發生的請求共享同一個實例,相應的,在設計Action類時就需要注意以下幾點:
不能使用實例或靜態變量存儲特定請求的狀態信息,它們會在同一個操作中共享跨越請求的全局資源,如果要訪問的資源(如JavaBean和會話變量)在並行訪問時需要進行保護,那麼訪問就要進行同步,Action類的方法
除了perform()方法外,還有以下方法:
可以獲得或設置與請求相關聯的區域:
public Locale getLocale(HttpServletRequest request)
public void setLocale(HttpServletRequest request,Localelocale)
爲應用程序獲得消息資源:
public MessageResources getResources()
檢查用戶是否點擊表單上的“取消”鍵,如果是,將返回true:
public Boolean isCancelled(HttpServletRequest request)
當應用程序發生錯誤時,Action類能夠使用下面方法存儲錯誤信息:
public void saveErrors(HttpServletRequestrequest,ActionErrors errors)
ActionError實例被用來存儲錯誤信息,這個方法在錯誤關鍵字下的請求屬性列表中存儲ActionError對象。通過使用在struts標記庫中定義的自定義標記,JSP頁能夠顯示這些錯誤信息,稍後我們就介紹。
3.5 ActionForm類
框架假設用戶在應用程序中爲每個表單都創建了一個ActionForm bean,對於每個在struts-config.xml文件中定義的bean,框架在調用Action類的perform()方法之前會進行以下操作:
l在相關聯的關鍵字下,它檢查用於適當類的bean實例的用戶會話,如果在會話中沒有可用的bean,它就會自動創建一個新的bean並添加到用戶的會話中。
對於請求中每個與bean屬性名稱對應的參數,Action調用相應的設置方法。l
當Action perform()被調用時,最新的ActionForml bean傳送給它,參數值就可以立即使用了。
ActionForm類擴展org.apache.struts.action.ActionForm類,程序開發人員創建的bean能夠包含額外的屬性,而且ActionServlet可能使用反射(允許從已加載的對象中回收信息)訪問它。
ActionForm類提供了另一種處理錯誤的手段,提供兩個方法:
Public ActionErrors validate(ActionMappin mapping,
ServletRequest request)
Public ActionErrors validate(ActionMappin mapping,
HttpServletRequest request)
你應該在自己的bean裏覆蓋validate()方法,並在配置文件裏設置<action>元素的validate爲true。在ActionServlet調用Action類前,它會調用validate(),如果返回的ActionErrors不是null,則ActinForm會根據錯誤關鍵字將ActionErrors存儲在請求屬性列表中。
如果返回的不是null,而且長度大於0,則根據錯誤關鍵字將實例存儲在請求的屬性列表中,然後ActionServlet將響應轉發到配置文件<action>元素的input屬性所指向的目標。
如果需要執行特定的數據有效性檢查,最好在Action類中進行這個操作,而不是在ActionForm類中進行。
方法reset()可將bean的屬性恢復到默認值:
public void reset(ActionMapping mapping,HttpServletRequestrequest)
public void reset(ActionMapping mapping,ServletRequestrequest)
典型的ActionFrom bean只有屬性的設置與讀取方法(getXXX),而沒有實現事務邏輯的方法。只有簡單的輸入檢查邏輯,使用的目的是爲了存儲用戶在相關表單中輸入的最新數據,以便可以將同一網頁進行再生,同時提供一組錯誤信息,這樣就可以讓用戶修改不正確的輸入數據。而真正對數據有效性進行檢查的是Action類或適當的事務邏輯bean。
3.6 ActionForward類
目的是控制器將Action類的處理結果轉發至目的地。
Action類獲得ActionForward實例的句柄,然後可用三種方法返回到ActionServlet,所以我們可以這樣使用findForward():
ActionServlet根據名稱獲取一個全局轉發,ActionMappin實例被傳送到perform()方法,並根據名稱找到一個本地轉發,另一種是調用下面的一個構造器來創建它們自己的一個實例:
public ActionForward()
public ActionForward(String path)
public ActionForward(String path,Boolean redirect)
----------------------------------------------------------------------------------------------------------------
在struts應用的生命週期中RequestProcessor只能保證一個Action實例,所有的其他請求都共享這個實例,因此Aciton是多線程進行工作,但是有一個保證正常和安全工作的前提是,Action不能有這樣的實例變量,擁有狀態的實例,尤其是擁有業務對象狀態的實例. 如果要用到那些有狀態的實例,唯一和最好的辦法是在Action類中,僅在Action類的execute()方法中使用局部變量,對於每個調用 execute()方法的線程,JVM會在每個線程的堆棧中創建局部變量,因此每個線程擁有獨立的局部變量,不會被其他線程共享.當線程執行完 execute()方法後,它的局部變量就會被銷燬.
現在項目中的做法:Action調用一個業務用例服務,這個服務本身沒有變量,這個服務來保證實現一個模型層的業務邏輯.如果Action類的實例變量是必須設定的話,需要採用JAVA同步機制對訪問共享資源的代碼塊進行同步.
----------------------------------------------------------------------------------------------------------------------
struts的action是非線程安全的。不要在action中定義實例變量。
在spring的配置文件中,可以配置action爲線程安全,即每次調用都生成一個新的實例,而不是隻用一個實例。
bean中設置singleton="true"
因爲控制器會令多個同時發生的請求共享同一個實例,所以最好不要在Action中使用實例或靜態變量存儲特定請求的狀態信息,如果要訪問相關的資源,最好進行同步操作。