對象的生命周期的管理是面向對象編程亘古不變的話題,從syntax的角度,面向對象的高級編程語言都是以“對象”為核心,而對象之間的繼承關系、嵌套引用關系構成的對象樹結構為我們進行對象級別的邏輯操作提供了足夠的語法支持。而對象之間的這種復雜的關系也為對象生命周期的管理帶了難題:
- 1.運行期,對象實例的創建和引用機制
- 2.對象及其關聯對象之間的依賴處理機制。
為了解決這個難題,業界在程序邏輯中引進了一個額外的編程元素(Container),
(由一系列操作對象的接口構成其中至少包括獲取對象實例和管理對象之間依賴關系的操作方法。)
首先讓我們先看看Struts的這個Container的構造吧。
從框架的角度其實Struts2實際運行有2條主線和2個執行階段。
Struts2的所有內容都無法逃脫這些概念存在。他們構成了Struts2的基本元素和運行機理。
第一條主線:Struts2的初始化:調用servlet之init方法執行。
該主線特點:
1.僅在web應用啟動時執行一次
2.init方法執行失敗將導致整個應用啟動失敗。這也是源於Filter這個servlet規范的基本運行特性。
Struts2這條初始化主線主要干的活:框架元素的初始化,包括框架內部許多內置對象的創建和緩存。
對框架的運行的必要條件進行控制(根據“開閉原則”框架的擴展開放保證了我們可以在應用層面對框架的運行參數以及執行模式進行定制,所以在這條主線中struts2也對這種定制化的正確性提供了運行時校驗,如果失敗,則web應用的啟動也會失敗。)
這條主線的順利執行將會為之后的Http請求提供“舒適的”執行環境,注意這里的運行環境並不是Struts2的運行環境,這里的環境是建立在web Container之上,框架運行必須的內置對象的集合。本次初始化也是對這個建立在web container之上的Container的初始化。
初始化涉及class如下:
第二條主線:Struts2的http請求處理主線,包括對http請求的處理、對必要數據的處理和返回數據的處理全過程。
即:從滿足StrutsPrepareAndExecuteFilter過濾url開始到dofilter方法執行。
本主線分兩個執行階段:
1.Http請求預處理 這也是程序的控制權真正在Strust2手上的時候。程序在這個階段是依賴web Container的。
本階段主要將分析http請求中以字符串形式的“弱類型”數據轉換成以對象為載體的“強類型”數據,以及為運行環境做准備。
2.XWork終於粉墨登場啦 O(∩_∩)O~ XWork執行業務邏輯
這個階段程序的控制權落入XWork之手。XWork依托於第一階段封裝的對象形式的數據,處理業務邏輯。
這個階段程序完全跟web Container沒啥關系了 這也是Struts2所說的之所以它不是不依賴於web Container的MVC框架的原因。
這也體現了Struts2的核心設計理念:消除了核心程序對於運行環境(Web Container)的依賴,也是Struts2解耦的過程。
1.代碼角度的解耦:第一執行階段的代碼整合到struts2-core-2.3.16.1.jar第二執行階段的代碼整合到xwork-core-2.3.16.1.jar
2.邏輯角度的解耦:將處理數據的邏輯和處理業務的邏輯分成倆個不同的執行階段處理。(但是現在紅極一時的SpringMVC卻又回歸了 重新擁入了Web Container的大懷抱啦 (⊙o⊙)…)
第二階段設計類如下:
了解了Struts2的大體流程,接下來我們再具體看一下XWork到底是怎么工作的。
首先,先讓我們來看看XWork Container這個"大盒子"是怎么定義的吧
- public interface Container extends Serializable {
- /**
- * Default dependency name.
- */
- String DEFAULT_NAME = "default";
- /**
- * Injects dependencies into the fields and methods of an existing object.
- */
- void inject(Object o);
- /**
- * Creates and injects a new instance of type {@code implementation}.
- */
- <T> T inject(Class<T> implementation);
- /**
- * Gets an instance of the given dependency which was declared in
- * {@link com.opensymphony.xwork2.inject.ContainerBuilder}.
- */
- <T> T getInstance(Class<T> type, String name);
- /**
- * Convenience method. Equivalent to {@code getInstance(type,
- * DEFAULT_NAME)}.
- */
- <T> T getInstance(Class<T> type);
- /**
- * Gets a set of all registered names for the given type
- * @param type The instance type
- * @return A set of registered names or empty set if no instances are registered for that type
- */
- Set<String> getInstanceNames(Class<?> type);
- /**
- * Sets the scope strategy for the current thread.
- */
- void setScopeStrategy(Scope.Strategy scopeStrategy);
- /**
- * Removes the scope strategy for the current thread.
- */
- void removeScopeStrategy();
- }
- String DEFAULT_NAME = "default";//默認的對象獲取標識
- void inject(Object o);//進行對象依賴注入的基本操作接口,作為參數的Object將被XWork Container進行處理,Object內部聲明有@Inject的字段和方法,都將被注入受到“盒子”托管的對象,從而建立起依賴關系
- <T> T inject(Class<T> implementation);//創建一個類的實例並進行對象依賴注入
- <T> T getInstance(Class<T> type, String name);//根據type和name作為唯一標識獲取聲明在com.opensymphony.xwork2.inject.ContainerBuilder的對象實例
- <T> T getInstance(Class<T> type);//根據type和默認的DEFAULT_NAME 作為唯一標識獲取“盒子”里的java類實例
- Set<String> getInstanceNames(Class<?> type);//通過type獲取這個type對應“盒子”中注冊過的name
- void setScopeStrategy(Scope.Strategy scopeStrategy);//設置當前線程的作用范圍的策略
- void removeScopeStrategy();//刪除當前線程的作用范圍的策略
個人覺得這個Container於Spring中的BeanFactory有着異曲同工之妙。