structs2 運行流程分析

相關的API:

ActionMapping:Simple class that holds the action mapping information used to invoke a Struts action. The name and namespace are required


ActionMapper:When given an HttpServletRequest, the ActionMapper may return null if no action invocation request matches, or it may return an ActionMapping that describes an action invocation for the framework to try


ActionProxy:ActionProxy is an extra layer between XWork and the action so that different proxies are possible. 


ActionInvocation:An ActionInvocation represents the execution state of an Action. It holds the Interceptors and the Action instance. By repeated re-entrant execution of the invoke() method, initially by the ActionProxy, then by the Interceptors, the Interceptors are all executed, and then the Action and the Result.

運行流程:

1. 請求發送給 StrutsPrepareAndExecuteFilter


2. StrutsPrepareAndExecuteFilter 詢問 ActionMapper: 該請求是否是一個 Struts2 請求(即是否返回一個非空的 ActionMapping 對象)


3. 若 ActionMapper 認爲該請求是一個 Struts2 請求,則 StrutsPrepareAndExecuteFilter 把請求的處理交給 ActionProxy


4. ActionProxy 通過 Configuration Manager 詢問框架的配置文件,確定需要調用的 Action 類及 Action 方法


5. ActionProxy 創建一個 ActionInvocation 的實例,並進行初始化


6. ActionInvocation 實例在調用Action的過程前後,涉及到相關攔截器(Intercepter)的調用。


7. Action 執行完畢,ActionInvocation 負責根據 struts.xml 中的配置找到對應的返回結果。調用結果的 execute 方法,渲染結果。在渲染的過程中可以使用Struts2 框架中的標籤。


8. 執行各個攔截器 invocation.invoke() 之後的代碼


9. 把結果發送到客戶端


——————————第二次編輯——————————————————


作者:郭無心
鏈接:https://www.zhihu.com/question/22027032/answer/74516331
來源:知乎

可以參看一個模擬struts2實現攔截器的例子:
//
Main文件(直接調用ActionInovocation的invoke方法進行循環執行interceptor)
public class Main {
	public static void main(String[] args) {
		new ActionInvocation().invoke();
	}
}


ActionInvocation文件(循環調用各interceptor的intercept方法,結束則調用action的execute方法)

import java.util.ArrayList;
import java.util.List;
public class ActionInvocation {
	List<Interceptor> interceptors = new ArrayList<Interceptor>();
	int index = -1;
	Action a = new Action();
	
	public ActionInvocation() {
		this.interceptors.add(new FirstInterceptor());
		this.interceptors.add(new SecondInterceptor());
	}
	
	public void invoke() {
		index ++;
		if(index >= this.interceptors.size()) {
			a.execute();
		}else { 
			this.interceptors.get(index).intercept(this);
		}
	}
}
FirstInterceptor文件(intercept方法重新調用ActionInvocation的invoke方法達到循環的效果)

public class FirstInterceptor implements Interceptor {
    public void intercept(ActionInvocation invocation){
		System.out.println(1);
		invocation.invoke();
		System.out.println(-1);
    }
}
//SecondInterceptor文件
public class SecondInterceptor implements Interceptor {
    public void intercept(ActionInvocation invocation) {
                System.out.println(2);
		invocation.invoke();
		System.out.println(-2);
	}
}


//Interceptor接口(intercept方法參數爲ActionInvocation)
public interface Interceptor {
    public void intercept(ActionInvocation invocation);
}

//Action類(action類,執行)
public class Action {
	public void execute() {
		System.out.println("execute!");
	}
}


1)攔截器(Interceptor)是Struts2的核心組成部分,是XWork體系的重要組件。
2)Struts2很多功能都是構建在攔截器基礎之上的,例如文件的上傳下載、國際化、數據類型轉換和數據校驗等等。
3)Struts2攔截器在訪問某個Action方法之前和之後實施攔截
4)Struts2攔截器是可插拔的,攔截器是AOP(面向切面編程)的一種實現。
5)攔截器棧(Interceptor Stack):將攔截器按一定的順序聯結成一條鏈,在訪問被攔截的方法時,Struts2攔截器鏈中的攔截器就會按其之前定義的順序依次調用。


&amp;lt;img src=&quot;https://pic1.zhimg.com/04ef3abf5fa3ffeff6b8783c30b0597c_b.png&quot; data-rawwidth=&quot;305&quot; data-rawheight=&quot;301&quot; class=&quot;content_image&quot; width=&quot;305&quot;&amp;gt;類似於FilterChain,但又有很大的不同,比如FilterChain需要在編寫doFilter方法時自行實現返回時的過濾以及鏈的向下執行,並且是在Servlet容器執行的這些操作。類似於FilterChain,但又有很大的不同,比如FilterChain需要在編寫doFilter方法時自行實現返回時的過濾以及鏈的向下執行,並且是在Servlet容器執行的這些操作。
相反Intercetor是通過反射,通過XWork容器調用,自動返回攔截。

每個攔截器都是實現了com.opensynphony.xwork2.interceptor.Interceptor接口的Java類
public interface Interceptor extends Serializable{
       void destroy();
       void init();
       String intercept(ActionInvocation invaocation) throws Exception;
}
---init : 該方法將在攔截器被創建後立即被調用,它在攔截器的生命週期內只被調用一次,可以在該方法中對相關資源進行必要的初始化。

---interecept : 每攔截一個請求該方法就會被調用一次。

---destroy: 該方法將在攔截器被銷燬之前被調用它在攔截器的生命週期內也只被調用一次。
這三個方法在Servlet和Filter當中都有這樣的類似定義,顯然這個攔截器也是單例模式的。

Struts2會依次調用爲某個Action而註冊的每一個攔截器的interecept方法。
每次調用interecept方法時,Struts2會傳遞一個ActionInvocation接口的實例。

ActionInvocation: 代表一個給定 Action 的執行狀態, 攔截器可以從該類的對象裏獲得與該 Action 相關聯的 Action 對象和 Result 對象. 在完成攔截器自己的任務之後, 攔截器將調用 ActionInvocation 對象的 invoke 方法前進到 Action 處理流程的下一個環節.
AbstractInterceptor 類實現了 Interceptor 接口. 併爲 init, destroy 提供了一個空白的實現

---------------------------------
自定義攔截器的步驟
1)定義一個攔截器的類
> 可以實現Interceptor接口
> 繼承AbstractInterceptor抽象類
2)在struts.xml 當中進行配置
例如我們的例子
<package name="default" namespace="/" extends="struts-default">
   <interceptors>
      <interceptor name="hello"  
               class="com.struts2.interceptors.MyInterceptor">
      </interceptor>
		
      <interceptor-stack name="atguigustack">

	 <interceptor-ref name="defaultStack">
	   <param name="fileUpload.maximumSize">2097152</param>
	   <!--  	
           <param name="fileUpload.allowedTypes">text/html,text/xml</param>
	   <param name="fileUpload.allowedExtensions">html,dtd,xml</param>
	   -->
           </interceptor-ref>

	</interceptor-stack>
   </interceptors>
		
   <default-interceptor-ref name="atguigustack">
   </default-interceptor-ref>
		
   <action name="testUpload" 
	class="com.struts2.upload.app.UploadAction">
	<result>/success.jsp</result>
	<result name="input">/upload.jsp</result>
   </action>
		
  <action name="testDownload"class="com.struts2.download.app.DownLoadAction">
	<result type="stream">
		<param name="bufferSize">2048</param>
	</result>
   </action>
		
<action name="testToken" class="com.struts2.token.app.TokenAction">
   <interceptor-ref name="hello"></interceptor-ref>
	<interceptor-ref name="tokenSession"></interceptor-ref>
		<interceptor-ref name="defaultStack"></interceptor-ref>
			<result>/success.jsp</result>
			<result name="invalid.token">/token-error.jsp</result>
		</action>
			
 </package>



------------------------------
一圖勝千言(感覺跟Servlet標準中的FilterChain模式實現不會有太多區別)&amp;lt;img src=&quot;https://pic2.zhimg.com/2ddff64c87f67c630f4265cac1777719_b.png&quot; data-rawwidth=&quot;960&quot; data-rawheight=&quot;720&quot; class=&quot;origin_image zh-lightbox-thumb&quot; width=&quot;960&quot; data-original=&quot;https://pic2.zhimg.com/2ddff64c87f67c630f4265cac1777719_r.png&quot;&amp;gt;&amp;lt;img src=&quot;https://pic2.zhimg.com/0095fecf492250c5bbdbd347cd49e5cd_b.png&quot; data-rawwidth=&quot;679&quot; data-rawheight=&quot;540&quot; class=&quot;origin_image zh-lightbox-thumb&quot; width=&quot;679&quot; data-original=&quot;https://pic2.zhimg.com/0095fecf492250c5bbdbd347cd49e5cd_r.png&quot;&amp;gt;--------------------------------------------------------------------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章