Struts2框架的執行流程
1.struts2的流程圖
2.描述執行流程
( 1 ). 客戶端初始化一個指向Servlet容器(例如Tomcat)的請求 (客戶端提交一個HttpServletRequest請求。)
(2)請求被提交到一系列的過濾器(Filter)。
如(ActionContextCleanUp、其他過濾器(SiteMesh等)、 FilterDispatcher。注意:這裡是有順序的,先ActionContext CleanUp,再其他過濾器(Othter Filters、SiteMesh等),最後到FilterDispatcher。
FilterDispatcher是控制器的核心,就是MVC的Struts 2實現中控制層(Controller)的核心。
常規情況官方推薦使用StrutsPrepareAndExecuteFilter替代FilterDispatcher。
(3)FilterDispatcher詢問ActionMapper是否需要呼叫某個Action來處理這個(HttpServlet Request)請求,如果ActionMapper決定需要呼叫某個Action,FilterDispatcher則把請求的處理交給ActionProxy。
(4) ActionProxy通過Configuration Manager(struts.xml)詢問框架的配置檔案,找到需要呼叫的Action類。
(5)ActionProxy建立一個ActionInvocation例項,同時ActionInvocation通過代理模式呼叫Action。(有點類似與遞迴操作)
(6)Action執行完畢後,ActionInvocation負責根據struts.xml中的配置找到對應的返回結果result。
3.簡單的過一遍原始碼
StrutsPrepareAndExecuteFilter類中的doFilter方法,需要注意這幾行。
89行 prepare.createActionContext(request, response);
//準備資料中心ActionContext.
91行 request = prepare.wrapRequest(request);
//進入對應的類(StrutsRequestWrapper)中注意 getAttribute(String key)方法,該方法會先從原聲的request中查詢,如果查詢不到會再從ValueStack中查詢
92行 ActionMapping mapping = prepare.findActionMapping(request, response, true);
//解析對應的action相關資訊
99行 execute.executeAction(request, response, mapping);
//該方法會呼叫Dispatcher類中的serviceAction方法
在該方法中注意:
String namespace = mapping.getNamespace();
String name = mapping.getName();
String method = mapping.getMethod();
ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
proxy.execute();
//該方法會呼叫StrutsActionProxy中的execute方法
//在execute方法中
invocation.invoke()
//該方法會呼叫DefaultActionInvocation中的invoke
if (interceptors.hasNext()) {
final InterceptorMapping interceptor = interceptors.next();
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
//這裡開始類似與遞迴呼叫
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
}finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
//注意:當執行玩所有的interceptor後,最後執行action
resultCode = invokeActionOnly();
}
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this)
//這句程式碼第一次會呼叫com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor中的intercept方法,在該方法中
result = invocation.invoke();
會又呼叫DefaultActionInvocation中的invoke() 。
如此遞迴的呼叫下去,
但是呼叫時會遵循一下的方式相互呼叫(ActionInvocation調Interceptor,Interceptor調ActionInvocation)
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
<interceptor-ref name="deprecation"/>
</interceptor-stack>
最後不滿足if中的條件會執行 resultCode = invokeActionOnly()
注意:這時還沒有給客戶端應答,只是生成了頁面 最後,按照相反的順序把interceptor執行完,最後傳給response展示結果。