章節(jié)簡(jiǎn)言

上一章筆者寫(xiě)關(guān)于Dispatcher類如何處理接受來(lái)的request請(qǐng)求。當(dāng)然讀者們也知道他并非正真的執(zhí)行action操作。他只是在執(zhí)行action操作之前的準(zhǔn)備工作。那么誰(shuí)才是正真的執(zhí)行action呢?本章筆者就帶大家來(lái)看看StrutsExecuteFilter類的工作。在理解StrutsExecuteFilter類的工作之前,筆者還是希望大家回顧一下前一章講到的request請(qǐng)求工作。為什么這樣子講呢?可以說(shuō)StrutsExecuteFilter類的工作是建立在StrutsPrepareFilter類基礎(chǔ)上運(yùn)行的。先相信這一點(diǎn)筆者不需要聲明了。筆者為了更好的理解小小的做一個(gè)張圖片。如下

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

從上面的圖片我們就是很清楚StrutsPrepareFilter類做了哪些工作。而圖上的上五點(diǎn)對(duì)于后面的StrutsExecuteFilter類來(lái)講是非常重要的。雖然我在前面幾章也提過(guò)StrutsExecuteFilter類的知識(shí)?!?a class="postTitle2" style="margin: 0px; padding: 0px; outline: none; color: black;">Struts2 源碼分析——過(guò)濾器(Filter)》章節(jié)里面也講過(guò)。只是很簡(jiǎn)單的略講一下。并沒(méi)有對(duì)他進(jìn)特別的講。主要是筆者認(rèn)為不了解StrutsPrepareFilter類的工作的情況下,去了解StrutsExecuteFilter類的話。是一件比較吃力的事情。好了。筆者就不多說(shuō)了。讓我們進(jìn)入本章的內(nèi)容吧。

調(diào)結(jié)者的執(zhí)行action

StrutsExecuteFilter類的工作就是執(zhí)行對(duì)應(yīng)的action請(qǐng)求。StrutsExecuteFilter類的工作還需要有一個(gè)叫ExecuteOperations類的幫助。如果看過(guò)源碼的朋友都知道,StrutsExecuteFilter類的代碼里用了ExecuteOperations類的倆個(gè)方法。一個(gè)是:executeStaticResourceRequest方法。一個(gè)是:executeAction方法。光從字名面上我就知道他們的功能。executeStaticResourceRequest是執(zhí)行靜態(tài)資源請(qǐng)求。如JS文件,css文件等。而executeAction就是執(zhí)行action請(qǐng)求。即是筆者想要講的重點(diǎn)。好了。還是讓我們先看一下StrutsExecuteFilter類代碼吧。如下部分代碼

StrutsExecuteFilter類:

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 2  3         HttpServletRequest request = (HttpServletRequest) req; 4         HttpServletResponse response = (HttpServletResponse) res; 5  6         if (excludeUrl(request)) {//用于判斷是否在排除的action之內(nèi)。如果是就跳過(guò)。 7             chain.doFilter(request, response); 8             return; 9         }10 11         if (execute == null) {12             lazyInit();//初始化相關(guān)的信息類。13         }14 15         ActionMapping mapping = prepare.findActionMapping(request, response);//找到ActionMapping實(shí)例16 17   18         Integer recursionCounter = (Integer) request.getAttribute(PrepareOperations.CLEANUP_RECURSION_COUNTER);19 20         if (mapping == null || recursionCounter > 1) {21             boolean handled = execute.executeStaticResourceRequest(request, response);//執(zhí)行請(qǐng)求css,js文件。并返回是否成功。22             if (!handled) {23                 chain.doFilter(request, response);24             }25         } else {26             execute.executeAction(request, response, mapping);//執(zhí)行action請(qǐng)求,重要部分27         }28     }

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

根據(jù)上面的紅色的代碼,讓筆者講一下總共做了幾件事件。

1.判斷當(dāng)前的request請(qǐng)求是不是被排在外。如果就跳過(guò)去。(筆者不想過(guò)講,太簡(jiǎn)單了)

2.判斷是否存在ExecuteOperations類的實(shí)例。如果沒(méi)有就初始化。相關(guān)的代碼如下。

StrutsExecuteFilter類:

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 1  /** 2      * 加載并初始化 3      */ 4     protected synchronized void lazyInit() { 5         if (execute == null) { 6             InitOperations init = new InitOperations();//用于初始化的功能類 7             Dispatcher dispatcher = init.findDispatcherOnThread();//StrutsPrepareFilter類的時(shí)候,就把Dispatcher實(shí)例存放在本地線程里面。這是只是把他拿出來(lái)。 8             init.initStaticContentLoader(new FilterHostConfig(filterConfig), dispatcher);//初始化用于加載css,js文件的加載類。 9             10             prepare = new PrepareOperations(dispatcher);11             execute = new ExecuteOperations(dispatcher);12         }13 14     }

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

看了代碼我們就知道StrutsExecuteFilter類的lazyInit方法做了什么。

1).找到對(duì)應(yīng)的Dispatcher實(shí)例。那么Dispatcher實(shí)例在哪里初始化呢?這就是StrutsPrepareFilter類的里面。(如果不理解的讀者,請(qǐng)轉(zhuǎn)至Struts2 源碼分析——調(diào)結(jié)者(Dispatcher)之a(chǎn)ction請(qǐng)求的章節(jié))

2).初始化StaticContentLoader類。即是用于加載JS,CSS文件等類似的加載類。

3).初始化相關(guān)對(duì)應(yīng)的PrepareOperations類和ExecuteOperations類。為了下面執(zhí)行action請(qǐng)求準(zhǔn)備。其中ExecuteOperations類很重要。用于執(zhí)行action和加載JS,CSS文件類似的調(diào)動(dòng)者。

 

3.找到對(duì)應(yīng)的action映射(ActionMapping類)。可以說(shuō)沒(méi)有action映射就沒(méi)有辦法執(zhí)行相關(guān)的action操作。讓我們看一下findActionMapping方法的代碼吧。

PrepareOperations類:

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 public ActionMapping findActionMapping(HttpServletRequest request, HttpServletResponse response, boolean forceLookup) {        ActionMapping mapping = (ActionMapping) request.getAttribute(STRUTS_ACTION_MAPPING_KEY);        if (mapping == null || forceLookup) {            try {                mapping = dispatcher.getContainer().getInstance(ActionMapper.class).getMapping(request, dispatcher.getConfigurationManager());                if (mapping != null) {                    request.setAttribute(STRUTS_ACTION_MAPPING_KEY, mapping);
                }
            } catch (Exception ex) {
                dispatcher.sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
            }
        }        return mapping;
    }

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

先從request請(qǐng)求中找到以STRUTS_ACTION_MAPPING_KEY常量為Key的ActionMapping值。如果不存在,則通過(guò)Container容器中找到的ActionMapper實(shí)例,并通過(guò)ActionMapper實(shí)例找到對(duì)應(yīng)的Action映射,并存于request請(qǐng)求。其Key值為STRUTS_ACTION_MAPPING_KEY常量。相信讀者又看Dispatcher類的實(shí)例了。又跟他有關(guān)系。關(guān)于這一步其實(shí)在StrutsPrepareFilter類工作的時(shí)候就已經(jīng)做過(guò)一次了。(在這里用到ActionMapper類。關(guān)于他的作用讀者目前只要知道所有的struts.xml上的配置action信息都在里面。筆者后面說(shuō)找一個(gè)章節(jié)講他)

 

4.如果沒(méi)有找到對(duì)應(yīng)的action映射(ActionMapping類)或action跳越的數(shù)量>1就是執(zhí)行加載JS,CSS文件的加載類。否則就是執(zhí)行action。實(shí)話實(shí)說(shuō)筆者真不知道recursionCounter > 1是什么個(gè)意思。我只能把他理解為跳轉(zhuǎn)的action數(shù)。筆者也做了相關(guān)通的實(shí)驗(yàn)就是希望看出一些事端??上×?。

先看一下executeStaticResourceRequest方法吧。對(duì)于executeStaticResourceRequest方法。筆者在上面就講到了。他是用于加載相關(guān)的靜態(tài)資源。如CSS文件,JS文件。這些文件是在JAR里面的。我們有時(shí)候struts2相關(guān)的UI的TAG的時(shí)候,就要加載對(duì)應(yīng)的CSS文件,和JS文件吧。這個(gè)時(shí)候他就啟作用了。讓我們看一下代碼吧。

ExecuteOperations類:

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 1     public boolean executeStaticResourceRequest(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { 2         // 如果沒(méi)有找到對(duì)應(yīng)的action,我們應(yīng)該看一下是不是請(qǐng)求靜態(tài)資源 3         String resourcePath = RequestUtils.getServletPath(request); 4  5         if ("".equals(resourcePath) && null != request.getPathInfo()) { 6             resourcePath = request.getPathInfo(); 7         } 8  9         StaticContentLoader staticResourceLoader = dispatcher.getContainer().getInstance(StaticContentLoader.class);10         if (staticResourceLoader.canHandle(resourcePath)) {11             staticResourceLoader.findStaticResource(resourcePath, request, response);12             return true;13 14         } else {15             // 如果不是的話,就表示他是一個(gè)普通的請(qǐng)求16             return false;17         }18     }

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

因?yàn)檫@部分不是筆者這系列要講的重點(diǎn)。如果有興趣的讀者可以自行繼續(xù)研發(fā)下去。我們可以看又是跟Dispatcher類的實(shí)例有關(guān)系。相信讀者這個(gè)時(shí)候很能明白筆者為什么說(shuō)Dispatcher類很重要。很能做很多事情。

關(guān)于執(zhí)行action的部分就在executeAction方法里面。讓我們看一下代碼吧。

ExecuteOperations類:

1  public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {2         dispatcher.serviceAction(request, response, mapping);3     }

好吧。我有一種打人的沖動(dòng)。Dispatcher類的實(shí)例又出現(xiàn)。執(zhí)行request請(qǐng)求的action也是Dispatcher類的實(shí)例來(lái)完成的。既然如此讓我們看一下代碼吧。如下

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 1 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) 2             throws ServletException { 3  4         Map<String, Object> extraContext = createContextMap(request, response, mapping); 5  6         //如果之前就有了值棧,就是新建一個(gè)新的值棧,放入extraContext 7         ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); 8         boolean nullStack = stack == null; 9         if (nullStack) {10             ActionContext ctx = ActionContext.getContext();11             if (ctx != null) {12                 stack = ctx.getValueStack();13             }14         }15         if (stack != null) {16             extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack));17         }18 19         String timerKey = "Handling request from Dispatcher";20         try {21             UtilTimerStack.push(timerKey);22             String namespace = mapping.getNamespace();//獲得request請(qǐng)求里面的命名空間,即是struts.xml是的package節(jié)點(diǎn)元素
23             String name = mapping.getName();//獲得request請(qǐng)求里面的action名
24             String method = mapping.getMethod();//要執(zhí)行action的方法25 26             ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name,27                     method, extraContext, true, false);//獲得action的代理28 29             request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());30 31             // 如果action映射是直接就跳轉(zhuǎn)到網(wǎng)頁(yè)的話,
32             if (mapping.getResult() != null) {
33                 Result result = mapping.getResult();
34                 result.execute(proxy.getInvocation());
35             } else {
36                 proxy.execute();//這里就是執(zhí)行action
37             }38 39             40             41             if (!nullStack) {42                 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);43             }44         } catch (ConfigurationException e) {45             logConfigurationException(request, e);46             sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);47         } catch (Exception e) {48             if (handleException || devMode) {49                 sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);50             } else {51                 throw new ServletException(e);52             }53         } finally {54             UtilTimerStack.pop(timerKey);55         }56     }

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 從上面的代碼就能看出在執(zhí)行action的內(nèi)部還需要用到一個(gè)叫ActionProxy類。關(guān)于這部分知識(shí),筆者其實(shí)這里不想講的很細(xì)。主要這部分的知識(shí)太多了。但這里筆者還是希望為后面的章節(jié)做好準(zhǔn)備。ActionProxy類可以理解他是一個(gè)代理。他的主要目地就是根據(jù)action映射得到的信息,尋找對(duì)應(yīng)action類實(shí)例,然后執(zhí)行對(duì)應(yīng)的方法。其中包括加載對(duì)應(yīng)的攔截器,初始化相應(yīng)的結(jié)果。而這段代碼中,在ActionProxy類的execute()方法的時(shí)候,還作了相應(yīng)的判斷。即是是否直接回返結(jié)果。其次還有在講到一個(gè)關(guān)于值棧的知識(shí)。這里在獲得ActionProxy類實(shí)例的時(shí)候,需要得到對(duì)應(yīng)值棧的信息。但是不管如何,最后一定會(huì)把request請(qǐng)求的值棧重新更新一下。ValueStack(值棧)的作用相信大家都懂。我就不做過(guò)多的講解了。

本章總結(jié)

可以說(shuō)相關(guān)Dispatcher類的知識(shí)點(diǎn),到本章節(jié)算是結(jié)束了。筆者把Dispatcher類的功能分為三點(diǎn):一是加載struts2運(yùn)行的必要條件信息;二是初始化action請(qǐng)求需要的信息;三是執(zhí)行request請(qǐng)求對(duì)應(yīng)的action。而關(guān)于核心機(jī)制圖片的橙色部分的工作大部分筆者都有體現(xiàn)出來(lái)。而后面的章節(jié)都是為了這三個(gè)功能點(diǎn)進(jìn)行的。所以希望讀者能理解這三個(gè)功能。