﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-黑夜里的狼-随笔分类-Struts2</title><link>http://www.blogjava.net/hellxoul/category/50246.html</link><description /><language>zh-cn</language><lastBuildDate>Fri, 14 Dec 2012 07:45:47 GMT</lastBuildDate><pubDate>Fri, 14 Dec 2012 07:45:47 GMT</pubDate><ttl>60</ttl><item><title>Struts2中的拦截器</title><link>http://www.blogjava.net/hellxoul/archive/2012/12/14/392970.html</link><dc:creator>hellxoul</dc:creator><author>hellxoul</author><pubDate>Fri, 14 Dec 2012 02:41:00 GMT</pubDate><guid>http://www.blogjava.net/hellxoul/archive/2012/12/14/392970.html</guid><wfw:comment>http://www.blogjava.net/hellxoul/comments/392970.html</wfw:comment><comments>http://www.blogjava.net/hellxoul/archive/2012/12/14/392970.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/hellxoul/comments/commentRss/392970.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/hellxoul/services/trackbacks/392970.html</trackback:ping><description><![CDATA[<div>接下来，我们将重点讨论一下Struts2中的拦截器的内部结构和执行顺序，并结合源码进行分析。            <div id="wiki_menu">       <h4>目 录 <a href="http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors#" title="隐藏/显示目录"><small>[ - ]</small></a></h4>       <ol><li><a href="http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors#1678">Interceptor结构</a></li><li><a href="http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors#1679">Interceptor执行分析</a></li><li><a href="http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors#1680">源码解析</a></li></ol>     </div>             <h2>         Interceptor结构         <a name="1678" href="http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors#top"><img alt="Top" src="http://www.iteye.com/images/wiki/top.gif?1324994303" /></a>                </h2>       <div>         让我们再来回顾一下之前我们曾经用过的一张Action LifeCycle的图： <br /> <br /><img src="http://www.iteye.com/upload/attachment/68182/ae963ed3-fae7-3710-bfcf-2fc49942ee90.png"  alt="" /> <br /> <br />图中，我们可以发现，Struts2的Interceptor一层一层，把Action包裹在最里面。这样的结构，大概有以下一些特点： <br /> <br /><strong>1. 整个结构就如同一个堆栈，除了Action以外，堆栈中的其他元素是Interceptor</strong> <br /> <br /><strong>2. Action位于堆栈的底部。由于堆栈"先进后出"的特性，如果我们试图把Action拿出来执行，我们必须首先把位于Action上端的Interceptor拿出来执行。这样，整个执行就形成了一个递归调用</strong> <br /> <br /><strong>3. 每个位于堆栈中的Interceptor，除了需要完成它自身的逻辑，还需要完成一个特殊的执行职责。这个执行职责有3种选择： <br /> <br /><span style="color: blue;">1) 中止整个执行，直接返回一个字符串作为resultCode</span> <br /> <br /><span style="color: blue;">2) 通过递归调用负责调用堆栈中下一个Interceptor的执行</span> <br /> <br /><span style="color: blue;">3) 如果在堆栈内已经不存在任何的Interceptor，调用Action</span> <br /></strong> <br /> <br />Struts2的拦截器结构的设计，实际上是一个典型的<strong>责任链模式</strong>的应用。首先将整个执行划分成若干相同类型的元素，每个元素具备不同的逻辑责任，并将他们纳入到一个链式的数据结构中（我们可以把堆栈结构也看作是一个递归的链式结构），而每个元素又有责任负责链式结构中下一个元素的执行调用。 <br /> <br />这样的设计，从代码重构的角度来看，实际上是将一个复杂的系统，分而治之，从而使得每个部分的逻辑能够高度重用并具备高度可扩展性。所以，Interceptor结构实在是Struts2/Xwork设计中的精华之笔。       </div>            <h2>         Interceptor执行分析         <a name="1679" href="http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors#top"><img alt="Top" src="http://www.iteye.com/images/wiki/top.gif?1324994303" /></a>                </h2>       <div>         <strong><span style="color: blue;">Interceptor的定义</span></strong> <br /> <br />我们来看一下Interceptor的接口的定义： <br /> <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://struts2.group.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>public&nbsp;interface&nbsp;Interceptor&nbsp;extends&nbsp;Serializable&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Called&nbsp;to&nbsp;let&nbsp;an&nbsp;interceptor&nbsp;clean&nbsp;up&nbsp;any&nbsp;resources&nbsp;it&nbsp;has&nbsp;allocated.&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>void&nbsp;destroy();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Called&nbsp;after&nbsp;an&nbsp;interceptor&nbsp;is&nbsp;created,&nbsp;but&nbsp;before&nbsp;any&nbsp;requests&nbsp;are&nbsp;processed&nbsp;using&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;{@link&nbsp;#intercept(com.opensymphony.xwork2.ActionInvocation)&nbsp;intercept}&nbsp;,&nbsp;giving&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;the&nbsp;Interceptor&nbsp;a&nbsp;chance&nbsp;to&nbsp;initialize&nbsp;any&nbsp;needed&nbsp;resources.&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>void&nbsp;init();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Allows&nbsp;the&nbsp;Interceptor&nbsp;to&nbsp;do&nbsp;some&nbsp;processing&nbsp;on&nbsp;the&nbsp;request&nbsp;before&nbsp;and/or&nbsp;after&nbsp;the&nbsp;rest&nbsp;of&nbsp;the&nbsp;processing&nbsp;of&nbsp;the&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;request&nbsp;by&nbsp;the&nbsp;{@link&nbsp;ActionInvocation}&nbsp;or&nbsp;to&nbsp;short-circuit&nbsp;the&nbsp;processing&nbsp;and&nbsp;just&nbsp;return&nbsp;a&nbsp;String&nbsp;return&nbsp;code.&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@return&nbsp;the&nbsp;return&nbsp;code,&nbsp;either&nbsp;returned&nbsp;from&nbsp;{@link&nbsp;ActionInvocation#invoke()},&nbsp;or&nbsp;from&nbsp;the&nbsp;interceptor&nbsp;itself.&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@throws&nbsp;Exception&nbsp;any&nbsp;system-level&nbsp;error,&nbsp;as&nbsp;defined&nbsp;in&nbsp;{@link&nbsp;com.opensymphony.xwork2.Action#execute()}.&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;intercept(ActionInvocation&nbsp;invocation)&nbsp;<span>throws&nbsp;Exception;&nbsp;&nbsp;</span></li><li>}&nbsp;&nbsp;</li></ol></div> <br /> <br />Interceptor的接口定义没有什么特别的地方，除了init和destory方法以外，intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是我们之前章节中曾经提到过的著名的<strong>Action调度者</strong>。 <br /> <br />我们再来看看一个典型的Interceptor的抽象实现类： <br /> <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://struts2.group.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>public&nbsp;abstract&nbsp;class&nbsp;AroundInterceptor&nbsp;extends&nbsp;AbstractInterceptor&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/*&nbsp;(non-Javadoc)&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@see&nbsp;com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation)&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>@Override&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;String&nbsp;intercept(ActionInvocation&nbsp;invocation)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;result&nbsp;=&nbsp;<span>null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;before(invocation);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;调用下一个拦截器，如果拦截器不存在，则执行Action&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;invocation.invoke();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;after(invocation,&nbsp;result);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;result;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;abstract&nbsp;void&nbsp;before(ActionInvocation&nbsp;invocation)&nbsp;throws&nbsp;Exception;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;abstract&nbsp;void&nbsp;after(ActionInvocation&nbsp;invocation,&nbsp;String&nbsp;resultCode)&nbsp;throws&nbsp;Exception;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <br /> <br />在这个实现类中，实际上已经实现了最简单的拦截器的雏形。或许大家对这样的代码还比较陌生，这没有关系。我在这里需要指出的是一个很重要的方法 invocation.invoke()。这是ActionInvocation中的方法，而ActionInvocation是Action调度者，所 以这个方法具备以下2层含义： <br /> <br /><strong>1. 如果拦截器堆栈中还有其他的Interceptor，那么invocation.invoke()将调用堆栈中下一个Interceptor的执行。</strong> <br /> <br /><strong>2. 如果拦截器堆栈中只有Action了，那么invocation.invoke()将调用Action执行。</strong> <br /> <br />所以，我们可以发现，invocation.invoke()这个方法其实是整个拦截器框架的实现核心。基于这样的实现机制，我们还可以得到下面2个非常重要的推论： <br /> <br /><strong>1. 如果在拦截器中，我们不使用invocation.invoke()来完成堆栈中下一个元素的调用，而是直接返回一个字符串作为执行结果，那么整个执行将被中止。</strong> <br /> <br /><strong>2.  我们可以以invocation.invoke()为界，将拦截器中的代码分成2个部分，在invocation.invoke()之前的代码，将会在 Action之前被依次执行，而在invocation.invoke()之后的代码，将会在Action之后被逆序执行。</strong> <br /> <br />由此，我们就可以通过invocation.invoke()作为Action代码真正的拦截点，从而实现AOP。 <br /> <br /><strong><span style="color: blue;">Interceptor拦截类型</span></strong> <br /> <br />从上面的分析，我们知道，整个拦截器的核心部分是invocation.invoke()这个函数的调用位置。事实上，我们也正式根据这句代码的调用位置，来进行拦截类型的区分的。在Struts2中，Interceptor的拦截类型，分成以下三类： <br /> <br /><strong>1. before</strong> <br /> <br />before拦截，是指在拦截器中定义的代码，它们存在于invocation.invoke()代码执行之前。这些代码，将依照拦截器定义的顺序，<strong>顺序执行</strong>。 <br /> <br /><strong>2. after</strong> <br /> <br />after拦截，是指在拦截器中定义的代码，它们存在于invocation.invoke()代码执行之后。这些代码，将一招拦截器定义的顺序，<strong>逆序执行</strong>。 <br /> <br />3. PreResultListener <br /> <br />有的时候，before拦截和after拦截对我们来说是不够的，因为我们需要在Action执行完之后，但是还没有回到视图层之前，做一些事 情。Struts2同样支持这样的拦截，这种拦截方式，是通过在拦截器中注册一个PreResultListener的接口来实现的。 <br /> <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://struts2.group.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>public&nbsp;interface&nbsp;PreResultListener&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>/**&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;This&nbsp;callback&nbsp;method&nbsp;will&nbsp;be&nbsp;called&nbsp;after&nbsp;the&nbsp;Action&nbsp;execution&nbsp;and&nbsp;before&nbsp;the&nbsp;Result&nbsp;execution.&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;invocation&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;resultCode&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>void&nbsp;beforeResult(ActionInvocation&nbsp;invocation,&nbsp;String&nbsp;resultCode);&nbsp;&nbsp;</span></li><li>}&nbsp;&nbsp;</li></ol></div> <br /> <br />在这里，我们看到，Struts2能够支持如此多的拦截类型，与其本身的数据结构和整体设计有很大的关系。正如我在之前的文章中所提到的： <br /> <br /><div>downpour 写道</div><div>因为Action是一个普通的Java类，而不是一个Servlet类，完全脱离于Web容器，所以我们就能够更加方便地对Control层进行合理的层次设计，从而抽象出许多公共的逻辑，并将这些逻辑脱离出Action对象本身。</div> <br /> <br />我们可以看到，Struts2对于整个执行的划分，从Interceptor到Action一直到Result，每一层都职责明确。不仅如此，Struts2还为每一个层次之前都设立了恰如其分的插入点。使得整个Action层的扩展性得到了史无前例的提升。 <br /> <br /><strong><span style="color: blue;">Interceptor执行顺序</span></strong> <br /> <br />Interceptor的执行顺序或许是我们在整个过程中最最关心的部分。根据上面所提到的概念，我们实际上已经能够大致明白了Interceptor的执行机理。我们来看看Struts2的Reference对Interceptor执行顺序的一个形象的例子。 <br /> <br />如果我们有一个interceptor-stack的定义如下： <br /> <br /><div id=""><div><div>Xml代码 &nbsp;<a title="收藏这段代码"><img src="http://struts2.group.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>&lt;interceptor-stack&nbsp;name="xaStack"&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>&lt;interceptor-ref&nbsp;name="thisWillRunFirstInterceptor"/&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>&lt;interceptor-ref&nbsp;name="thisWillRunNextInterceptor"/&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>&lt;interceptor-ref&nbsp;name="followedByThisInterceptor"/&gt;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;<span>&lt;interceptor-ref&nbsp;name="thisWillRunLastInterceptor"/&gt;&nbsp;&nbsp;</span></li><li><span>&lt;/interceptor-stack&gt;&nbsp;&nbsp;</span></li></ol></div> <br /> <br />那么，整个执行的顺序大概像这样： <br /> <br /><img src="http://struts2.group.iteye.com/upload/attachment/71392/23045c94-b72a-3c04-9c6c-06ad4392d743.gif"  alt="" /> <br /> <br />在这里，我稍微改了一下Struts2的Reference中的执行顺序示例，使得整个执行顺序更加能够被理解。我们可以看到，递归调用保证了各种各样的拦截类型的执行能够井井有条。 <br /> <br />请注意在这里，每个拦截器中的代码的执行顺序，在Action之前，拦截器的执行顺序与堆栈中定义的一致；而在Action和Result之后，拦截器的执行顺序与堆栈中定义的顺序相反。 <br />       </div>            <h2>         源码解析         <a name="1680" href="http://struts2.group.iteye.com/group/wiki/1397-deep-into-struts2-interceptors#top"><img alt="Top" src="http://www.iteye.com/images/wiki/top.gif?1324994303" /></a>                </h2>                接下来我们就来看看源码，看看Struts2是如何保证拦截器、Action与Result三者之间的执行顺序的。 <br /> <br />之前我曾经提到，ActionInvocation是Struts2中的调度器，所以事实上，这些代码的调度执行，是在 ActionInvocation的实现类中完成的，这里，我抽取了DefaultActionInvocation中的invoke()方法，它将向我 们展示一切。 <br /> <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://struts2.group.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>/**&nbsp;</span></li><li><span>&nbsp;*&nbsp;@throws&nbsp;ConfigurationException&nbsp;If&nbsp;no&nbsp;result&nbsp;can&nbsp;be&nbsp;found&nbsp;with&nbsp;the&nbsp;returned&nbsp;code&nbsp;</span></li><li><span>&nbsp;*/&nbsp;&nbsp;</span></li><li><span>public&nbsp;String&nbsp;invoke()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;profileKey&nbsp;=&nbsp;<span>"invoke:&nbsp;";&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.push(profileKey);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(executed)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>throw&nbsp;new&nbsp;IllegalStateException("Action&nbsp;has&nbsp;already&nbsp;executed");&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;依次调用拦截器堆栈中的拦截器代码执行&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(interceptors.hasNext())&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>final&nbsp;InterceptorMapping&nbsp;interceptor&nbsp;=&nbsp;(InterceptorMapping)&nbsp;interceptors.next();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.profile(<span>"interceptor:&nbsp;"+interceptor.getName(),&nbsp;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>new&nbsp;UtilTimerStack.ProfilingBlock&lt;String&gt;()&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>public&nbsp;String&nbsp;doProfiling()&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;将ActionInvocation作为参数，调用interceptor中的intercept方法执行&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resultCode&nbsp;=&nbsp;interceptor.getInterceptor().intercept(DefaultActionInvocation.<span>this);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span>else&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resultCode&nbsp;=&nbsp;invokeActionOnly();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;this&nbsp;is&nbsp;needed&nbsp;because&nbsp;the&nbsp;result&nbsp;will&nbsp;be&nbsp;executed,&nbsp;then&nbsp;control&nbsp;will&nbsp;return&nbsp;to&nbsp;the&nbsp;Interceptor,&nbsp;which&nbsp;will&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;return&nbsp;above&nbsp;and&nbsp;flow&nbsp;through&nbsp;again&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(!executed)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;执行PreResultListener&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(preResultListeners&nbsp;!=&nbsp;null)&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>for&nbsp;(Iterator&nbsp;iterator&nbsp;=&nbsp;preResultListeners.iterator();&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iterator.hasNext();)&nbsp;{&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PreResultListener&nbsp;listener&nbsp;=&nbsp;(PreResultListener)&nbsp;iterator.next();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;_profileKey=<span>"preResultListener:&nbsp;";&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>try&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.push(_profileKey);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listener.beforeResult(<span>this,&nbsp;resultCode);&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>finally&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.pop(_profileKey);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;now&nbsp;execute&nbsp;the&nbsp;result,&nbsp;if&nbsp;we're&nbsp;supposed&nbsp;to&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;action与interceptor执行完毕，执行Result&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>if&nbsp;(proxy.getExecuteResult())&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executeResult();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executed&nbsp;=&nbsp;<span>true;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;resultCode;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;<span>finally&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.pop(profileKey);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</li><li>}&nbsp;&nbsp;</li></ol></div> <br /> <br />从源码中，我们可以看到，我们之前提到的Struts2的Action层的4个不同的层次，在这个方法中都有体现，他们分别是：拦截器 （Interceptor）、Action、PreResultListener和Result。在这个方法中，保证了这些层次的有序调用和执行。由此我 们也可以看出<strong><span style="color: red;">Struts2在Action层次设计上的众多考虑，每个层次都具备了高度的扩展性和插入点，使得程序员可以在任何喜欢的层次加入自己的实现机制改变Action的行为。</span></strong> <br /> <br />在这里，需要特别强调的，是其中拦截器部分的执行调用： <br /> <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://struts2.group.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>resultCode&nbsp;=&nbsp;interceptor.getInterceptor().intercept(DefaultActionInvocation.this);&nbsp;&nbsp;</span></li></ol></div> <br /> <br />表面上，它只是执行了拦截器中的intercept方法，如果我们结合拦截器来看，就能看出点端倪来： <br /> <br /><div id=""><div><div>Java代码 &nbsp;<a title="收藏这段代码"><img src="http://struts2.group.iteye.com/images/icon_star.png" alt="收藏代码" /></a></div></div><ol start="1"><li><span>public&nbsp;String&nbsp;intercept(ActionInvocation&nbsp;invocation)&nbsp;throws&nbsp;Exception&nbsp;{&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;result&nbsp;=&nbsp;<span>null;&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;before(invocation);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>//&nbsp;调用invocation的invoke()方法，在这里形成了递归调用&nbsp;&nbsp;</span></li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;invocation.invoke();&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;after(invocation,&nbsp;result);&nbsp;&nbsp;</li><li>&nbsp;&nbsp;</li><li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span>return&nbsp;result;&nbsp;&nbsp;</span></li><li>}&nbsp;&nbsp;</li></ol></div> <br /> <br />原来在intercept()方法又对ActionInvocation的invoke()方法进行递归调用，ActionInvocation 循环嵌套在intercept()中，一直到语句result =  invocation.invoke()执行结束。这样，Interceptor又会按照刚开始执行的逆向顺序依次执行结束。</div><img src ="http://www.blogjava.net/hellxoul/aggbug/392970.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/hellxoul/" target="_blank">hellxoul</a> 2012-12-14 10:41 <a href="http://www.blogjava.net/hellxoul/archive/2012/12/14/392970.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>