這是Struts2官方站點提供的Struts 2 的整體結構。
一個請求在Struts2框架中的處理大概分為以下幾個步驟:
- 客戶端提起一個(HttpServletRequest)請求,如上文在瀏覽器中輸入”http://localhost:8080/TestMvc/add.action”就是提起一個(HttpServletRequest)請求。
- 請求被提交到一系列(主要是三層)的過濾器(Filter),如(ActionContextCleanUp、其他過濾器(SiteMesh等)、 FilterDispatcher)。注意這里是有順序的,先ActionContextCleanUp,再其他過濾器(SiteMesh等)、最后到FilterDispatcher。
-
FilterDispatcher是控制器的核心,就是mvc中c控制層的核心。下面粗略的分析下我理解的FilterDispatcher工作流程和原理:FilterDispatcher進行初始化并啟用核心doFilter
其代碼如下:
- public ? void ?doFilter(ServletRequest?req,?ServletResponse?res,?FilterChain?chain)? throws ?IOException,?ServletException?...{
- ????????HttpServletRequest?request?=?(HttpServletRequest)?req;
- ????????HttpServletResponse?response?=?(HttpServletResponse)?res;
- ????????ServletContext?servletContext?=?filterConfig.getServletContext();
- ???????? //?在這里處理了HttpServletRequest和HttpServletResponse。
- ????????DispatcherUtils?du?=?DispatcherUtils.getInstance();
- ????????du.prepare(request,?response); //正如這個方法名字一樣進行locale、encoding以及特殊request?parameters設置
- ???????? try ?...{
- ????????????request?=?du.wrapRequest(request,?servletContext); //對request進行包裝
- ????????}? catch ?(IOException?e)?...{
- ????????????String?message?=? "Could?not?wrap?servlet?request?with?MultipartRequestWrapper!" ;
- ????????????LOG.error(message,?e);
- ???????????? throw ? new ?ServletException(message,?e);
- ????????}
- ????????????????ActionMapperIF?mapper?=?ActionMapperFactory.getMapper(); //得到action的mapper
- ????????ActionMapping?mapping?=?mapper.getMapping(request); //?得到action?的?mapping
- ???????? if ?(mapping?==? null )?...{
- ???????????? //?there?is?no?action?in?this?request,?should?we?look?for?a?static?resource?
- ????????????String?resourcePath?=?RequestUtils.getServletPath(request);
- ???????????? if ?( "" .equals(resourcePath)?&&? null ?!=?request.getPathInfo())?...{
- ????????????????resourcePath?=?request.getPathInfo();
- ????????????}
- ???????????? if ?( "true" .equals(Configuration.get(WebWorkConstants.WEBWORK_SERVE_STATIC_CONTENT))?
- ????????????????????&&?resourcePath.startsWith( "/webwork" ))?...{
- ????????????????String?name?=?resourcePath.substring( "/webwork" .length());
- ????????????????findStaticResource(name,?response);
- ????????????}? else ?...{
- ???????????????? //?this?is?a?normal?request,?let?it?pass?through
- ????????????????chain.doFilter(request,?response);
- ????????????}
- ???????????? //?WW?did?its?job?here
- ???????????? return ;
- ????????}
- ????????Object?o?=? null ;
- ???????? try ?...{
- ???????????? //setupContainer(request);
- ????????????o?=?beforeActionInvocation(request,?servletContext);
- //整個框架最最核心的方法,下面分析
- ????????????du.serviceAction(request,?response,?servletContext,?mapping);
- ????????}? finally ?...{
- ????????????afterActionInvocation(request,?servletContext,?o);
- ????????????ActionContext.setContext( null );
- ????????}
- ????}
- du.serviceAction(request,?response,?servletContext,?mapping);
- //這個方法詢問ActionMapper是否需要調用某個Action來處理這個(request)請求,如果ActionMapper決定需要調用某個Action,FilterDispatcher把請求的處理交給ActionProxy
- public ? void ?serviceAction(HttpServletRequest?request,?HttpServletResponse?response,?String?namespace,?String?actionName,?Map?requestMap,?Map?parameterMap,?Map?sessionMap,?Map?applicationMap)?...{?
- ????????HashMap?extraContext?=?createContextMap(requestMap,?parameterMap,?sessionMap,?applicationMap,?request,?response,?getServletConfig());?? //實例化Map請求?,詢問ActionMapper是否需要調用某個Action來處理這個(request)請求
- ????????extraContext.put(SERVLET_DISPATCHER,? this );?
- ????????OgnlValueStack?stack?=?(OgnlValueStack)?request.getAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY);?
- ???????? if ?(stack?!=? null )?...{?
- ????????????extraContext.put(ActionContext.VALUE_STACK, new ?OgnlValueStack(stack));?
- ????????}?
- ???????? try ?...{?
- ????????????ActionProxy?proxy?=?ActionProxyFactory.getFactory().createActionProxy(namespace,?actionName,?extraContext);?
- //這里actionName是通過兩道getActionName解析出來的,?FilterDispatcher把請求的處理交給ActionProxy,下面是ServletDispatcher的?TODO:?
- ????????????request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY,?proxy.getInvocation().getStack());?
- ????????????proxy.execute();?
- ????????? //通過代理模式執行ActionProxy
- ???????????? if ?(stack?!=? null )...{?
- ????????????????request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY,stack);?
- ????????????}?
- ????????}? catch ?(ConfigurationException?e)?...{?
- ????????????log.error( "Could?not?find?action" ,?e);?
- ????????????sendError(request,?response,?HttpServletResponse.SC_NOT_FOUND,?e);?
- ????????}? catch ?(Exception?e)?...{?
- ????????????log.error( "Could?not?execute?action" ,?e);?
- ????????????sendError(request,?response,?HttpServletResponse.SC_INTERNAL_SERVER_ERROR,?e);?
- ????????}?
- }?
-
ActionProxy通過Configuration Manager(struts.xml)詢問框架的配置文件,找到需要調用的Action類.
如上文的struts.xml配置
- <? xml ? version = "1.0" ? encoding = "GBK" ?>
- ? <!DOCTYPE?struts?PUBLIC?"-//Apache?Software?Foundation//DTD?Struts?Configuration?2.0//EN"?"http://struts.apache.org/dtds/struts-2.0.dtd">
- ? < struts >
- ????? < include ? file = "struts-default.xml" />
- ????? < package ? name = "struts2" ? extends = "struts-default" >
- ????????? < action ? name = "add" ?
- ????????????? class = "edisundong.AddAction" ? >
- ????????????? < result > add.jsp </ result >
- ????????? </ action > ????
- ????? </ package >
- ? </ struts >
-
ActionProxy創建一個ActionInvocation的實例,同時ActionInvocation通過代理模式調用Action。但在調用之前ActionInvocation會根據配置加載Action相關的所有Interceptor。(Interceptor是struts2另一個核心級的概念)
下面我們來看看ActionInvocation是如何工作的:
ActionInvocation 是Xworks 中Action 調度的核心。而對Interceptor 的調度,也正是由ActionInvocation負責。ActionInvocation 是一個接口, 而DefaultActionInvocation 則是Webwork 對ActionInvocation的默認實現。
Interceptor 的調度流程大致如下:
1. ActionInvocation初始化時,根據配置,加載Action相關的所有Interceptor。
2. 通過ActionInvocation.invoke方法調用Action實現時,執行Interceptor。
Interceptor將很多功能從我們的Action中獨立出來,大量減少了我們Action的代碼,獨立出來的行為具有很好的重用性。XWork、WebWork的許多功能都是有Interceptor實現,可以在配置文件中組裝Action用到的Interceptor,它會按照你指定的順序,在Action執行前后運行。
那么什么是攔截器。
攔截器就是AOP(Aspect-Oriented Programming)的一種實現。(AOP是指用于在某個方法或字段被訪問之前,進行攔截然后在之前或之后加入某些操作。)
攔截器的例子這里就不展開了。
struts-default.xml文件摘取的內容:
- < ? interceptor ? name ?= "alias" ? class ?= "com.opensymphony.xwork2.interceptor.AliasInterceptor" ? /> ?
- < ? interceptor ? name ?= "autowiring" ? class ?= "com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor" ? /> ?
- < ? interceptor ? name ?= "chain" ? class ?= "com.opensymphony.xwork2.interceptor.ChainingInterceptor" ? /> ?
- < ? interceptor ? name ?= "conversionError" ? class ?= "org.apache.struts2.interceptor.StrutsConversionErrorInterceptor" ? /> ?
- < ? interceptor ? name ?= "createSession" ? class ?= "org.apache.struts2.interceptor.CreateSessionInterceptor" ? /> ?
- < ? interceptor ? name ?= "debugging" ? class ?= "org.apache.struts2.interceptor.debugging.DebuggingInterceptor" ? /> ?
- < ? interceptor ? name ?= "external-ref" ? class ?= "com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor" ? /> ?
- < ? interceptor ? name ?= "execAndWait" ? class ?= "org.apache.struts2.interceptor.ExecuteAndWaitInterceptor" ? /> ?
- < ? interceptor ? name ?= "exception" ? class ?= "com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor" ? /> ?
- < ? interceptor ? name ?= "fileUpload" ? class ?= "org.apache.struts2.interceptor.FileUploadInterceptor" ? /> ?
- < ? interceptor ? name ?= "i18n" ? class ?= "com.opensymphony.xwork2.interceptor.I18nInterceptor" ? /> ?
- < ? interceptor ? name ?= "logger" ? class ?= "com.opensymphony.xwork2.interceptor.LoggingInterceptor" ? /> ?
- < ? interceptor ? name ?= "model-driven" ? class ?= "com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor" ? /> ?
- < ? interceptor ? name ?= "scoped-model-driven" ? class ?= "com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor" ? /> ?
- < ? interceptor ? name ?= "params" ? class ?= "com.opensymphony.xwork2.interceptor.ParametersInterceptor" ? /> ?
- < ? interceptor ? name ?= "prepare" ? class ?= "com.opensymphony.xwork2.interceptor.PrepareInterceptor" ? /> ?
- < ? interceptor ? name ?= "static-params" ? class ?= "com.opensymphony.xwork2.interceptor.StaticParametersInterceptor" ? /> ?
- < ? interceptor ? name ?= "scope" ? class ?= "org.apache.struts2.interceptor.ScopeInterceptor" ? /> ?
- < ? interceptor ? name ?= "servlet-config" ? class ?= "org.apache.struts2.interceptor.ServletConfigInterceptor" ? /> ?
- < ? interceptor ? name ?= "sessionAutowiring" ? class ?= "org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor" ? /> ?
- < ? interceptor ? name ?= "timer" ? class ?= "com.opensymphony.xwork2.interceptor.TimerInterceptor" ? /> ?
- < ? interceptor ? name ?= "token" ? class ?= "org.apache.struts2.interceptor.TokenInterceptor" ? /> ?
- < ? interceptor ? name ?= "token-session" ? class ?= "org.apache.struts2.interceptor.TokenSessionStoreInterceptor" ? /> ?
- < ? interceptor ? name ?= "validation" ? class ?= "com.opensymphony.xwork2.validator.ValidationInterceptor" ? /> ?
- < ? interceptor ? name ?= "workflow" ? class ?= "com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor" ? /> ?
- < ? interceptor ? name ?= "store" ? class ?= "org.apache.struts2.interceptor.MessageStoreInterceptor" ? /> ?
- < ? interceptor ? name ?= "checkbox" ? class ?= "org.apache.struts2.interceptor.CheckboxInterceptor" ? /> ?
- < ? interceptor ? name ?= "profiling" ? class ?= "org.apache.struts2.interceptor.ProfilingActivationInterceptor" ? /> ?
總結:
Struts2的工作流就只有這7步,比起Struts1簡單了很多(本人能力有限,struts2更多的東西現在還看不明白)。網上有很多很多的關于.net和java的比較之類的文章,可是有幾個作者是真正用過java和.net的呢?更多的評論都是人云亦云,想當然的評論java和.net。作為技術人千萬不要屁股決定腦袋,關于web的設計模式上.net也不是那么一無是處,java也不是那么完美無缺。下一篇分析下ASP.NET的設計模式(生命周期)。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
