1. 程式人生 > >[Java面試四]Strust2總結及在面試中的一些問題.

[Java面試四]Strust2總結及在面試中的一些問題.

[Java面試四]Strust2總結及在面試中的一些問題.

1. JavaEE軟體三層結構和MVC的區別?

JavaEE軟體三層機構是由sun公司提供JavaEE開發規範的:Web層(表現層)、業務邏輯層、資料持久層。【其中WEB層會使用前端控制器模式】 
MVC是一種思想,是一種模式,將軟體分為 Model模型、View檢視、Controller控制器。【JavaEE開發更強調三層結構,web層開發更注重MVC】 
Struts2 就是web層開發框架,符合MVC模式;struts1 、webwork 、jsf 、SpringMVC 都是MVC

2. Struts和struts2的區別有哪些?

Action類  
Struts 1要求Action類要擴充套件自一個抽象基類。Struts 1的一個共有的問題是面向抽象類程式設計而不是面向介面程式設計。 
Struts 2的Action類實現了一個Action介面,連同其他介面一起實現可選擇和自定義的服務。Struts 2提供一個名叫ActionSupport的基類實現一般使用的介面。雖然,Action介面不是必須的。任何使用execute方法的POJO物件可以 被當作Struts 2的Action物件使用。  
程模型 


Struts 1 Action類是單例類,因只有一個示例控制所有的請求。單例類策略造成了一定的限制且給開發帶來了額外的煩惱。Action資源必須是程安全或者同步 的。 
Struts 2 Action物件每一個請求都例項化物件,所以沒有程安全的問題。(實踐中,servlet容器生許多丟的物件對於每一個請求,多於一個的物件並不影響垃 圾收集) 
Servlet 依賴 
Struts 1的Action類依賴於servlet API以HttpServletRequest和HttpServletResponse作引數傳給execute方法當Action被呼叫時。 
Struts 2的Action不和容器有關。Servlet上下文被表現簡單的Maps,允許Action被獨立的測試。Struts 2的Action可以訪問最初的請求和相應,如果需要的話。然而,其他的架構元素少或者排除直接訪問HttpServletRequest或者 HttpServletResponse的需要。  
易測性 

測試Struts 1的主要障礙是execute方法暴露了Servlet API。第三方的擴充套件,Struts測試用例,提供Struts 1的集合物件。 
Struts 2的Action可以通過例項化Action測試,設定屬性,然後呼叫方法。依賴注入的支援也是測試變得更簡單。 
接受輸入 
Struts 1使用ActionForm物件捕獲輸入。象Action一樣,所有的ActionForm必須擴充套件基類。因其他的JavaBean不能作 ActionForm使用,開發者經常建立多餘的類捕獲輸入。DynaBeans可以被用來作替代ActionForm的類建立。但是開發者可以重新描述 已經存在的JavaBean。 
Struts 2 Action屬性作輸入屬性,排除第二個輸入物件的需要。輸入屬性可能有豐富的物件型別這些型別有他們自己的屬性。Action的屬性可以通過標籤庫訪 問。Struts 2也支援ActionForm形式。豐富的物件型別,包含業務或者域物件,可以被當作輸入或者輸出物件使用。饃型驅動特性簡化標籤對POJO輸入物件的引 用。 
表示式語言 
Struts 1整和JSTL,所以它使用JSTL的表示式語言。表示式語言有基本的圖形物件移動,但是相對很弱的集合和被索引的屬性支援。 
Struts 2使用JSTL,但是框架也支援更大和更靈活的表示式,叫做“物件圖形符號語言”(OGNL)。 
將值繫結要檢視上 
Struts 1使用標準JSP機制來繫結物件到頁面上下文。 
Struts 2使用“ValueStack”技術了標籤庫可以不用連結你的檢視到物件的表現型別訪問值。ValueStack策略允許重用檢視。 
型別轉換 
Struts 1的ActionForm屬性經常都是String的。Struts 1使用Commons-Beanutils型別轉換。轉換每一個類,不是每一個例項配置。 
Struts 2使用OGNL型別轉換。框架包含轉換器基本的和共同的物件型別和原始型別。 
驗證 
Struts 1支援手動驗證憑藉ActionForm的validate方法,或者通過擴充套件的公用驗證器。類可以有不同的驗證上下文未相同的類,但是不能不能包括驗證 子物件。 
Struts 2支援手動驗證憑藉validate方法和XWork驗證框架。Xwork驗證框架支援一連串的驗證子屬性使用的驗證了屬性類的型別和嚴正上下文而定義。 
Action執行的控制 
Struts 1支援獨立的請求處理器對於每一個模型,但是所有在模型中的Action必須共享同一個生命週期。 
Struts 2支援在每一個Action基礎上憑藉攔截棧建立不同的生命週期。自定義棧可以被建立且使用不同的所需 的Action。

3. 簡要說說Struts2的處理流程?

Struts2框架的大致處理流程如下:

1、載入類(FilterDispatcher) 

2、讀取配置(struts配置檔案中的Action) 

3、派發請求(客戶端傳送請求) 

4、呼叫Action(FilterDispatcher從struts配置檔案中讀取與之相對應的Action ) 

5、啟用攔截器(WebWork攔截器鏈自動對請求應用通用功能,如驗證) 

6、處理業務(回撥Action的execute()方法) 

7、返回響應(通過execute方法將資訊返回到FilterDispatcher) 

8、查詢響應(FilterDispatcher根據配置查詢響應的是什麼資訊如:SUCCESS、ERROER,將跳轉到哪個jsp頁面) 

9、響應使用者(jsp--->客戶瀏覽器端顯示) 

10、struts2標籤庫(相比struts1的標籤庫,struts2是大大加強了,對資料的操作功能很強大)

wps5845.tmp9d4c8f2b-8f7e-48bf-87c4-d3ea4b65b8ba 

請求(.action)---->經過StrutsPrepareAndExecuteFilter 核心控制器---->進入到Struts2的攔截器Interceptor(實現程式碼功能)----->通過action的名稱找對應的Action類----->執行Action類的execute方法----->通過execute方法中返回的字串,在Struts.xml中找對應的結果頁面(result)【在action執行之前,執行了defaultStack攔截器棧

* 攔截器 在 struts-default.xml定義 【它位於sruts2-core-xxx.jar目錄下】

* 執行攔截器 是 defaultStack 中引用攔截器

4、Struts2配置檔案載入順序

    通過檢視StrutsPrepareAndExecuteFilter原始碼可以得到答案!

        82dc781d-960c-4ea8-81d9-9055e7e9c44c   

    此處,我們以及清晰了看到了該類載入配置檔案的順序,我們依次圍繞標號檢視對應方法產生的檔案即可。

 

    be5b51bc-149e-4e9a-baaf-1db4992d7cf9 

    對應產生檔案依次如下: 

 

   init_DefaultProperties(); // [1]----  org/apache/struts2/default.properties

 

    init_TraditionalXmlConfigurations(); // [2] --- struts-default.xml,struts-plugin.xml,struts.xml

 

    init_LegacyStrutsProperties(); // [3] --- 自定義struts.properties

 

    init_CustomConfigurationProviders(); // [5]  ----- 自定義配置提供

 

    init_FilterInitParameters() ; // [6] ----- web.xml

 

    init_AliasStandardObjects() ; // [7] ---- Bean載入

結論 :【前三個是預設的,不用關注,後面三個需要注意】

 

    ① default.properties 該檔案儲存在 struts2-core-2.3.7.jar 中 org.apache.struts2包裡面  (常量的預設值) 
    ② struts-default.xml 該檔案儲存在 struts2-core-2.3.7.jar  (Bean、攔截器、結果型別 ) 
    ③ struts-plugin.xml 該檔案儲存在struts-Xxx-2.3.7.jar  (在外掛包中存在 ,配置外掛資訊 )struts-config-browser-plugin-2.3.7.jar裡面有 
    ④ struts.xml 該檔案是web應用預設的struts配置檔案 (實際開發中,通常寫struts.xml ) 
    ⑤ struts.properties 該檔案是Struts的預設配置檔案  (配置常量 ) 
    ⑥ web.xml 該檔案是Web應用的配置檔案 (配置常量 )

後加載配置檔案中修改的常量的值會覆蓋前面配置檔案修改的常量的值!

5、我們在書寫Action的時候有哪幾種方式?他們有什麼區別?

有三種方式:

    ①普通POJO(簡單Java物件),這種方式我們不需要繼承任何父類,實現任何介面。Struts2框架讀取struts.xml檔案,獲得完整的action類名。

  1. obj =Class.forName("完整類名").newInstance();
  2. Method m =Class.forName("完整類名").getMethod("execute");
  3. m.invoke(obj);//通過反射 執行execute()方法

    ②編寫Action實現Action介面

  1. Action介面中,定義預設五種邏輯檢視名稱
  2. // 資料處理成功 (成功頁面)
  3. publicstatic final String SUCCESS ="success";
  4. // 頁面不跳轉 return null; 效果一樣
  5. publicstatic final String NONE ="none";
  6. // 資料處理傳送錯誤 (錯誤頁面)
  7. publicstatic final String ERROR ="error";
  8. // 使用者輸入資料有誤,通常用於表單資料校驗 (輸入頁面)
  9. publicstatic final String INPUT ="input";
  10. // 主要許可權認證 (登陸頁面)
  11. publicstatic final String LOGIN ="login";

    ③編寫Action繼承ActionSupport(推薦)

在Action中使用表單校驗、錯誤資訊設定、讀取國際化資訊三個功能

  1. 代理模式,控制目標物件訪問
  2. /hello.action 請求時StrutsPrepareAndExecuteFilter doFilter一定執行
  3. //判斷配置檔案中有沒有對應Action
  4. ActionMapping mapping = prepare.findActionMapping(request, response,true);
  5. //根據配置建立代理物件
  6. ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, method, extraContext,true,false);
  7. 執行時:先執行interceptorintercept攔截方法,最後指向actionexecute

6、Action是如何接受請求引數的?

屬性驅動和模型驅動  

Struts2內部提供了引數封裝功能,不需要使用BeanUtils進行封裝。Struts2大部分內建功能都是攔截器實現的。

    a1fbe5b3-bf27-47fa-8d05-dc7e5a4daa8d 

    當點選登入提交表單時,就會被下面的攔截器進行封裝,進行set注入值,實現引數封裝。

<interceptor name="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

 

第一種 :Action 本身作為model物件,通過成員setter封裝 (屬性驅動 )

    主要用於引數較少的封裝,如果分層,不利於將資料傳遞到業務層。 

    頁面:       

使用者名稱:<inputtype="text"name="username"/><br/>

    Action:

publicclassRegistAction1extendsActionSupport{

privateString username;

publicvoid setUsername(String username){

this.username = username;

}

}

    Struts2 action是多例項,不會有執行緒安全問題,使用這種資料封裝方式,資料封裝到action屬性中,不能將action物件傳遞給業務層,我們需要再單獨定義javabean,將action屬性封裝到javabean。

 

第二種 :建立獨立model物件,頁面通過ognl表示式封裝 (屬性驅動)

    具體封裝流程如下:傳遞username,呼叫setUsername,把username注入User中,將會新建一個User物件,當第二個引數password傳遞過來時,struts框架將首先呼叫getUser方法詢問User是否為空,如果為空,將會新建一個User,否則不會新建,直接注入值。如果只有一個Set方法,那麼每set一次資料,就會新建一個User物件,那麼就是把username、password封裝在兩個不同的User物件中了。這樣封裝失敗。

    頁面:

<!--基於OGNL表示式的寫法-->

使用者名稱:<inputtype="text"name="user.username"/><br/>

密 碼:<inputtype="password"name="user.password"/><br/>

    model(User):

publicclassUser{

privateString username;

privateString password;

publicString getUsername(){

return username;

}

publicvoid setUsername(String username){

this.username = username;

}

publicString getPassword(){

return password;

}

publicvoid setPassword(String password){

this.password = password;

}

}

    Action:

publicclassRegistAction2extendsActionSupport{

    privateUser user;

publicvoid setUser(User user){

    this.user = user;

}

//必須提供get方法(封裝第一個引數時,建立新的User物件, 封裝第二個引數需要使用第一個建立user物件)

publicUser getUser(){

    return user;

    }

}

    由params的攔截器完成引數的封裝

<interceptorname="params"class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>

 

第三種 :使用ModelDriven介面,對請求資料進行封裝 (模型驅動 ) ----- 企業開發的主流(模型驅動有很多特性)

<interceptorname="modelDriven"class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/> 為模型驅動提供了更多特性

    頁面:

使用者名稱:<inputtype="text"name="username"/><br/> 

    model(User):

    

    Action :

publicclassRegistAction3extendsActionSupportimplementsModelDriven<User>{

// 模型物件必須手動例項化

    privateUser user =newUser();

publicUser getModel(){

    return user;

}

}

    對比第二種、第三種 : 第三種只能在Action中指定一個model物件(返回一個model物件),第二種可以在Action中定義多個model物件

<inputtype="text"name="user.username"/> 

<inputtype="text"name="product.info"/>

 

7、Action的相關配置?

  1)必須要為<action>元素 配置<package>元素  (struts2 圍繞package進行Action的相關配置 )

    配置package 三個常用屬性

 

<packagename="default"namespace="/"extends="struts-default">

    ①name包名稱,在struts2的配置檔案中,包名不能重複,name並不是真正包名,只是為了管理Action

 

    ②namespace和 <action>的name屬性,決定 Action的訪問路徑  (以/開始 )

       namespace=""        :預設的名稱空間 
        namespace="/"       :根名稱空間 
        namespace="/aa/"    :帶有名稱空間的路徑

    ③extends繼承哪個包,通常開發中繼承struts-default包  (struts-default包在 struts-default.xml中定義 )【可以使用包中預設的攔截器和結果集】

    2)Action是通過<action>元素配置

 

<action name="hello"class="cn.itcast.struts2.demo1.HelloAction" method="execute">

    ①<action>的name和 <package>的namespace屬性共同決定 Action的訪問路徑

    ②class:類全路徑 

    ③method:執行的方法,預設為execute()方法 

 

例如:

 

<package name="default"namespace="/user" extends="struts-default">

    <action name="hello"class="cn.itcast.struts2.demo1.HelloAction">

        <result name="success">/demo1/success.jsp</result>

    </action>

</package>

此時的訪問路徑 http://localhost:8080/Struts2/demo1/user/hello.action

    ①result中的name:結果頁面邏輯檢視名稱,預設為success 

    ②type:結果型別(後面會做詳細介紹,預設為轉發) 

 

3) <action> 元素配置預設值

    <package> 的namespace 預設值 / 
    <action> 的class 預設值 ActionSupport 類     <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />    
    <result> 的 name 預設值 success

8、Action訪問Servlet API有哪幾種方式,簡單的介紹一下

①.方式一:使用ActionContext物件(在Action中解耦合方式間接訪問Servlet API)

    在struts2中Action API已經與Servlet API 解耦合(沒有依賴關係),開發簡單,便於測試。

    Servlet API 常見操作 : 表單提交請求引數獲取,向request、session、application三個範圍存取資料  

②.方式二:使用介面注入的方式操作Servlet API(藕合)

    通過Aware介面,在構造Action時,自動注入需要操作Servlet物件(需要哪個物件就實現哪個Aware介面)

③.方式三:在Action中直接通過 ServletActionContext 獲得Servlet API

    靜態方法返回request,不會有執行緒問題(使用了ThreadLocal來實現的)

總結:理論來說,第一種方式最好,實現瞭解耦和,但是第三種我們使用最為簡單,企業中沒有很大的限制,自己熟悉哪種就使用哪種。

9. 說說Struts2的輸入校驗流程

Struts2校驗框架進行校驗時,將執行以下流程: 

A:型別轉換器負責對字串的請求引數執行型別轉換,並將這些值設定成Action的屬性值

B:在執行型別轉換過程中可能出現異常,如果出現異常,將異常資訊儲存到ActionContext中,convertionError攔截器將負責將其封裝到fieldError裡,如果沒有異常,直接進入第3步

C:呼叫Struts2的內建校驗規則進行輸入校驗

D:通過反射呼叫validateXXX()方法

E:呼叫Action類中的validate()方法

F:如果上面的幾步中沒有出FiledError,就呼叫Acton中的邏輯處理方法,如果有,則進入input檢視

所以,在進行校驗時,別忘記在Action中的配置名為input的結果如:<result name=“input”>validate.jsp</result>

10. Struts2 form標籤資料為什麼可以回顯?

221e0239-ad18-4104-8809-3d21ff0545e1

11. 什麼是值棧?值棧的內部結構?

    ValueStack 是 struts2 提供一個介面,實現類 OgnlValueStack ---- 值棧物件 (OGNL是從值棧中獲取資料的 )每個Action例項都有一個ValueStack物件 (一個請求對應 一個ValueStack物件 )在其中儲存當前Action 物件和其他相關物件 (值棧中是有Action引用的 )Struts 框架把 ValueStack 物件儲存在名為“struts.valueStack” 的請求屬性中,request中(值棧物件是request一個屬性)

 

fc54671a-5c84-4d5f-bae5-c1fe7c10a96d

    值棧由兩部分組成,ObjectStack和ContextMap

ObjectStack: Struts 把動作和相關物件壓入 ObjectStack 中--List 
ContextMap: Struts 把各種各樣的對映關係(一些 Map 型別的物件) 壓入ContextMap中,Struts 會把下面這些對映壓入 ContextMap 中 

parameters: 該 Map 中包含當前請求的請求引數

request: 該 Map 中包含當前 request 物件中的所有屬性

session: 該 Map 中包含當前 session 物件中的所有屬性

application:該 Map 中包含當前 application  物件中的所有屬性

attr: 該 Map 按如下順序來檢索某個屬性: request, session, application

 

VaValueStack中 存在root屬性 (CompoundRoot) 、 context 屬性 (OgnlContext ) 
    * CompoundRoot 就是ArrayList 
    * OgnlContext 就是 Map

cncontext 對應Map 引入 root物件 
    * context中還存在 request、 session、application、 attr、 parameters 物件引用 
    * OGNL表示式,訪問root中資料時 不需要 #, 訪問 request、 session、application、 attr、 parameters 物件資料 必須寫 # 
    * 操作值棧 預設指 操作 root 元素

12. 值棧物件的建立 ,ValueStack 和 ActionContext 是什麼關係 ?

值棧物件是請求時建立的

doFilter中 prepare.createActionContext(request, response);

    * 建立ActionContext物件過程中,建立值棧物件ValueStack

    * ActionContext物件對ValueStack物件有引用的(在程式中通過 ActionContext 獲得值棧物件 )

Dispatcher類 serviceAction 方法中將值棧物件儲存到request範圍

    request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

13.如何獲得值棧物件?

獲得值棧物件 有兩種方法

    ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

    ValueStack valueStack2 = ActionContext.getContext().getValueStack();

14.如何向值棧中儲存資料?如何在jsp頁面中獲取值棧的資料?

兩種方式

    // 將資料儲存root的索引0位置,放置到第一個元素 ArrayList add(0,element);

    valueStack.push("itcast");

    // 在值棧建立引數map, 將資料儲存到map中

    valueStack.set("company", "傳智播客");

在jsp中 通過 <s:debug /> 檢視值棧的內容

wps47E6.tmpf2c502e0-4ca5-4aff-8a59-31d4f84bc177 

 

 

獲取值棧資料時,如果訪問root中資料不需要# ,訪問其它物件資料加 #

通過下標獲取root中物件

<s:property value="[0].top"/> //取值棧頂物件

直接在root中查詢物件屬性 (自上而下自動查詢)

valueStack:<s:property value="username"/>

 

在OgnlContext中獲取資料

request:<s:property value="#request.username"/>

session:<s:property value="#session.username"/>

application:<s:property value="#application.username"/>

attr:<s:property value="#attr.username"/>

parameters:<s:property value="#parameters.cid[0]"/>

15.為什麼EL也能訪問值棧中的資料?

StrutsPreparedAndExecuteFilter的doFilter程式碼中 request = prepare.wrapRequest(request); 

* 對Request物件進行了包裝 ,StrutsRequestWrapper

* 重寫request的 getAttribute

Object attribute = super.getAttribute(s);

if (attribute == null) {

    attribute = stack.findValue(s);

}

訪問request範圍的資料時,如果資料找不到,去值棧中找

16.你在開發中,值棧主要有哪些應用?

值棧主要解決Action向JSP傳遞資料問題

Action 向JSP 傳遞資料處理結果 ,結果資料有兩種形式

1)訊息 String型別資料

this.addFieldError("msg", "欄位錯誤資訊");

this.addActionError("Action全域性錯誤資訊");

this.addActionMessage("Action的訊息資訊");

* fieldError 針對某一個欄位錯誤資訊 (常用於表單校驗)、actionError (普通錯誤資訊,不針對某一個欄位 登陸失敗)、 actionMessage 通用訊息 

 

在jsp中使用 struts2提供標籤 顯示訊息資訊

<s:fielderror fieldName="msg"/>

<s:actionerror/>

<s:actionmessage/>

 

2)資料 (複雜型別資料)

使用值棧  valueStack.push(products);

哪些資料預設會放入到值棧 ???

1)每次請求,訪問Action物件 會被壓入值棧 ------- DefaultActionInvocation 的 init方法 stack.push(action);

    * Action如果想傳遞資料給 JSP,只有將資料儲存到成員變數,並且提供get方法就可以了

2)ModelDriven 介面有一個單獨攔截器

<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>

在攔截器中,將model物件壓入了值棧 stack.push(model);

    * 如果Action 實現ModelDriven介面,值棧預設棧頂物件就是model物件

17.如何防止表單重複提交?

哪些情況會導致重複提交?

    伺服器處理服務後,轉發頁面,客戶端點選重新整理(重定向)

    客戶端網路過慢,按鈕連續點選(按鈕點選一次後,禁用按鈕) 

使用令牌機制

b427a734-9313-4184-8f56-e1ed7ec248a0

18.簡單的說一下ActionProxy的執行原理?

Struts2的攔截器的本質就是AOP思想,而AOP就是基於代理模式。

6d59bb08-7c9c-4357-8d60-33e4ae386272

19.攔截器和過濾器有什麼區別?

1、①攔截器是基於java的反射機制的,而過濾器是基於函式回撥

2、②過濾器依賴與servlet容器,而攔截器不依賴與servlet容器

3、③攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用

4、④攔截器可以訪問action上下文、值棧裡的物件,而過濾器不能

5、⑤在action的生命週期中,攔截器可以多次被呼叫,而過濾器只能在容器初始化時被呼叫一次

攔  攔截器 :是在面向切面程式設計的就是在你的service或者一個方法,前呼叫一個方法,或者在方法後呼叫一個方法比如動態代理就是攔截器的簡單實現,在你呼叫方法前打印出字串(或者做其它業務邏輯的操作),也可以在你呼叫方法後打印出字串,甚至在你丟擲異常的時候做業務邏輯的操作。

20.Struts2詳細執行流程

1a8db227-399d-420f-9baa-b8f699e8e08b

    請求首先通過Filter chain,Filter主要包括ActionContextCleanUp,它主要清理當前執行緒的ActionContext和Dispatcher;FilterDispatcher主要通過AcionMapper來決定需要呼叫哪個Action。 

    ActionMapper取得了ActionMapping後,在Dispatcher的serviceAction方法裡建立ActionProxy,ActionProxy建立ActionInvocation,然後ActionInvocation呼叫Interceptors,執行Action本身,建立Result並返回,當然,如果要在返回之前做些什麼,可以實現PreResultListener。

 

部分類介紹

    ①ActionMapper

    ActionMapper其實是HttpServletRequest和Action呼叫請求的一個對映,它遮蔽了Action對於Request等java Servlet類的依賴。Struts2中它的預設實現類是DefaultActionMapper,ActionMapper很大的用處可以根據自己的需要來設計url格式,它自己也有Restful的實現,具體可以參考文件的docs\actionmapper.html。

    ②ActionProxy&ActionInvocation

    Action的一個代理,由ActionProxyFactory建立,它本身不包括Action例項,預設實現DefaultActionProxy是由ActionInvocation持有Action例項。ActionProxy作用是如何取得Action,無論是本地還是遠端。而ActionInvocation的作用是如何執行Action,攔截器的功能就是在ActionInvocation中實現的。

    ③ConfigurationProvider&Configuration

    ConfigurationProvider就是Struts2中配置檔案的解析器,Struts2中的配置檔案主要是尤其實現類XmlConfigurationProvider及其子類StrutsXmlConfigurationProvider來解析。

 

Struts2請求流程

    1、客戶端傳送請求

    2、請求先通過ActionContextCleanUp-->FilterDispatcher

    3、FilterDispatcher通過ActionMapper來決定這個Request需要呼叫哪個Action

    4、如果ActionMapper決定呼叫某個Action,FilterDispatcher把請求的處理交給ActionProxy,這兒已經轉到它的Delegate--Dispatcher來執行

    5、ActionProxy根據ActionMapping和ConfigurationManager找到需要呼叫的Action類

    6、ActionProxy建立一個ActionInvocation的例項

    7、ActionInvocation呼叫真正的Action,當然這涉及到相關攔截器的呼叫

    8、Action執行完畢,ActionInvocation建立Result並返回,當然,如果要在返回之前做些什麼,可以實現PreResultListener。新增PreResultListener可以在Interceptor中實現。

 

原始碼分析

     ①啟動伺服器(tomcat)將會自動載入配置檔案,載入過程如下:

        伺服器啟動,init()方法被執行

    f419c63f-0661-4a59-8e42-5ad749c7dc79 

    ②客戶端初始化一個指向Servlet容器(WEB容器)的請求; 

 

    ③這個請求經過一系列的過濾器(Filter)(這些過濾器中有一個叫做ActionContextCleanUp的可選過濾器,這個過濾器對於Struts2和其他框架的整合很有幫助,例如:(SiteMesh Plugin)。 

 

    ④接著StrutsPrepareAndExecuteFilter被呼叫,StrutsPrepareAndExecuteFilter詢問ActionMapper來決定這個請求是否需要呼叫某個Action。 

    1e88f4ef-8221-43cb-8a30-623b22914f11

 

    ⑤如果ActionMapper決定需要呼叫某個Action,FilterDispatcher把請求的處理交給ActionProxy。ActionProxy通過Configuration Manager詢問框架的配置檔案,找到需要呼叫的Action類

    86e6da23-691b-4d67-9e7e-f32845dfb909 

   

    ⑥ActionProxy建立一個ActionInvocation的例項。ActionInvocation例項使用命名模式來呼叫,在呼叫Action的過程前後,涉及到相關攔截器(Intercepter)的呼叫。攔截器預設執行<default-interceptor-ref name="defaultStack"/>defaultStack裡面有一系列的interceptor。

 

    ⑦一旦Action執行完畢,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果。返回結果通常是(但不總是,也可能是另外的一個Action鏈)一個需要被表示的JSP或者FreeMarker的模版。在表示的過程中可以使用Struts2框架中繼承的標籤。在這個過程中需要涉及到ActionMapper,響應的返回是通過我們在web.xml中配置的過濾器 

 

    ⑧如果ActionContextCleanUp是當前使用的,則FilterDispatecher將不會清理threadlocal ActionContext;如果ActionContextCleanUp不使用,則將會去清理threadlocals。