﻿<?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-JAVA &amp; XML &amp; JAVASCRIPT &amp; AJAX &amp; CSS -文章分类-Struts2</title><link>http://www.blogjava.net/fantasy/category/38008.html</link><description>Web 2.0 技术储备............</description><language>zh-cn</language><lastBuildDate>Mon, 02 Mar 2009 13:53:32 GMT</lastBuildDate><pubDate>Mon, 02 Mar 2009 13:53:32 GMT</pubDate><ttl>60</ttl><item><title>(转)拦截器深入实践</title><link>http://www.blogjava.net/fantasy/articles/257349.html</link><dc:creator>Web 2.0 技术资源</dc:creator><author>Web 2.0 技术资源</author><pubDate>Mon, 02 Mar 2009 07:24:00 GMT</pubDate><guid>http://www.blogjava.net/fantasy/articles/257349.html</guid><wfw:comment>http://www.blogjava.net/fantasy/comments/257349.html</wfw:comment><comments>http://www.blogjava.net/fantasy/articles/257349.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/fantasy/comments/commentRss/257349.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fantasy/services/trackbacks/257349.html</trackback:ping><description><![CDATA[<div class="content"><a href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#top">转自：http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#top</a><br />
<br />
在之前的文章中，我们已经涉及到了拦截器（Interceptor）的概念。 <br />
<br />
<div class="quote_title">downpour 写道</div>
<div class="quote_div">拦截器是AOP中的概念，它本身是一段代码，可以通过定义&#8220;织入点&#8221;，来指定拦截器的代码在&#8220;织入点&#8221;的前后执行，从而起到拦截的作用。正如上面 Struts2的Reference中讲述的，Struts2的Interceptor，其拦截的对象是Action代码，可以定义在Action代码之前或者之后执行拦截器的代码。 </div>
<br />
<br />
接下来，我们将重点讨论一下Struts2中的拦截器的内部结构和执行顺序，并结合源码进行分析。 </div>
<div id="wiki_menu">
<h4>目 录 <a title="隐藏/显示目录" onclick="$$('#wiki_menu ol')[0].toggle();return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><small>[ - ]</small></a></h4>
<ol>
    <li><a href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#1678">Interceptor结构</a>
    <li><a href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#1679">Interceptor执行分析</a>
    <li><a href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#1680">源码解析</a> </li>
</ol>
</div>
<h2>Interceptor结构 <a href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#top" name="1678"><img alt="Top" src="http://www.javaeye.com/images/wiki/top.gif?1229402183" /></a> </h2>
<div class="content">让我们再来回顾一下之前我们曾经用过的一张Action LifeCycle的图： <br />
<br />
<img alt="" src="http://www.javaeye.com/upload/attachment/68182/ae963ed3-fae7-3710-bfcf-2fc49942ee90.png" /> <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 href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#top" name="1679"><img alt="Top" src="http://www.javaeye.com/images/wiki/top.gif?1229402183" /></a> </h2>
<div class="content"><strong><span style="color: blue">Interceptor的定义</span></strong> <br />
<br />
我们来看一下Interceptor的接口的定义： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">interface</span><span>&nbsp;Interceptor&nbsp;</span><span class="keyword">extends</span><span>&nbsp;Serializable&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span>
    <li><span><span class="comment">&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. </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">void</span><span>&nbsp;destroy(); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span>
    <li><span><span class="comment">&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 </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;{@link&nbsp;#intercept(com.opensymphony.xwork2.ActionInvocation)&nbsp;intercept}&nbsp;,&nbsp;giving </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;the&nbsp;Interceptor&nbsp;a&nbsp;chance&nbsp;to&nbsp;initialize&nbsp;any&nbsp;needed&nbsp;resources. </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">void</span><span>&nbsp;init(); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span>
    <li><span><span class="comment">&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 </span>&nbsp;</span>
    <li><span><span class="comment">&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. </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* </span>&nbsp;</span>
    <li><span><span class="comment">&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. </span>&nbsp;</span>
    <li><span><span class="comment">&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()}. </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;intercept(ActionInvocation&nbsp;invocation)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception; &nbsp;&nbsp;</span></span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">public interface Interceptor extends Serializable {
/**
* Called to let an interceptor clean up any resources it has allocated.
*/
void destroy();
/**
* Called after an interceptor is created, but before any requests are processed using
* {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving
* the Interceptor a chance to initialize any needed resources.
*/
void init();
/**
* Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
* request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.
*
* @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.
* @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}.
*/
String intercept(ActionInvocation invocation) throws Exception;
}
</pre>
<br />
<br />
Interceptor的接口定义没有什么特别的地方，除了init和destory方法以外，intercept方法是实现整个拦截器机制的核心方法。而它所依赖的参数ActionInvocation则是我们之前章节中曾经提到过的著名的<strong>Action调度者</strong>。 <br />
<br />
我们再来看看一个典型的Interceptor的抽象实现类： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;AroundInterceptor&nbsp;</span><span class="keyword">extends</span><span>&nbsp;AbstractInterceptor&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/*&nbsp;(non-Javadoc) </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@see&nbsp;com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation) </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="annotation">@Override</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;String&nbsp;intercept(ActionInvocation&nbsp;invocation)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;result&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;before(invocation); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;调用下一个拦截器，如果拦截器不存在，则执行Action </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;invocation.invoke(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;after(invocation,&nbsp;result); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;result; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;before(ActionInvocation&nbsp;invocation)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">abstract</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;after(ActionInvocation&nbsp;invocation,&nbsp;String&nbsp;resultCode)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">public abstract class AroundInterceptor extends AbstractInterceptor {
/* (non-Javadoc)
* @see com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com.opensymphony.xwork2.ActionInvocation)
*/
@Override
public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
before(invocation);
// 调用下一个拦截器，如果拦截器不存在，则执行Action
result = invocation.invoke();
after(invocation, result);
return result;
}
public abstract void before(ActionInvocation invocation) throws Exception;
public abstract void after(ActionInvocation invocation, String resultCode) throws Exception;
}</pre>
<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 class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">interface</span><span>&nbsp;PreResultListener&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">/** </span>&nbsp;</span>
    <li><span><span class="comment">&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. </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;invocation </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;@param&nbsp;resultCode </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">void</span><span>&nbsp;beforeResult(ActionInvocation&nbsp;invocation,&nbsp;String&nbsp;resultCode); &nbsp;&nbsp;</span></span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">public interface PreResultListener {
/**
* This callback method will be called after the Action execution and before the Result execution.
*
* @param invocation
* @param resultCode
*/
void beforeResult(ActionInvocation invocation, String resultCode);
}
</pre>
<br />
<br />
在这里，我们看到，Struts2能够支持如此多的拦截类型，与其本身的数据结构和整体设计有很大的关系。正如我在之前的文章中所提到的： <br />
<br />
<div class="quote_title">downpour 写道</div>
<div class="quote_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 class="dp-highlighter">
<div class="bar">
<div class="tools">Xml代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-xml">
    <li><span><span class="tag">&lt;</span><span class="tag-name">interceptor-stack</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"xaStack"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">interceptor-ref</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"thisWillRunFirstInterceptor"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">interceptor-ref</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"thisWillRunNextInterceptor"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">interceptor-ref</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"followedByThisInterceptor"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">interceptor-ref</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"thisWillRunLastInterceptor"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></span>
    <li><span class="tag">&lt;/</span><span class="tag-name">interceptor-stack</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre class="xml" style="display: none" name="code">&lt;interceptor-stack name="xaStack"&gt;
&lt;interceptor-ref name="thisWillRunFirstInterceptor"/&gt;
&lt;interceptor-ref name="thisWillRunNextInterceptor"/&gt;
&lt;interceptor-ref name="followedByThisInterceptor"/&gt;
&lt;interceptor-ref name="thisWillRunLastInterceptor"/&gt;
&lt;/interceptor-stack&gt;</pre>
<br />
<br />
那么，整个执行的顺序大概像这样： <br />
<br />
<img alt="" src="http://www.javaeye.com/upload/attachment/71392/23045c94-b72a-3c04-9c6c-06ad4392d743.gif" /> <br />
<br />
在这里，我稍微改了一下Struts2的Reference中的执行顺序示例，使得整个执行顺序更加能够被理解。我们可以看到，递归调用保证了各种各样的拦截类型的执行能够井井有条。 <br />
<br />
请注意在这里，每个拦截器中的代码的执行顺序，在Action之前，拦截器的执行顺序与堆栈中定义的一致；而在Action和Result之后，拦截器的执行顺序与堆栈中定义的顺序相反。 <br />
</div>
<h2>源码解析 <a href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#top" name="1680"><img alt="Top" src="http://www.javaeye.com/images/wiki/top.gif?1229402183" /></a> </h2>
<div class="content">接下来我们就来看看源码，看看Struts2是如何保证拦截器、Action与Result三者之间的执行顺序的。 <br />
<br />
之前我曾经提到，ActionInvocation是Struts2中的调度器，所以事实上，这些代码的调度执行，是在ActionInvocation的实现类中完成的，这里，我抽取了DefaultActionInvocation中的invoke()方法，它将向我们展示一切。 <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">/** </span>&nbsp;</span>
    <li><span><span class="comment">&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 </span>&nbsp;</span>
    <li><span><span class="comment">&nbsp;*/</span><span>&nbsp;&nbsp;</span></span>
    <li><span class="keyword">public</span><span>&nbsp;String&nbsp;invoke()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;profileKey&nbsp;=&nbsp;</span><span class="string">"invoke:&nbsp;"</span><span>; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.push(profileKey); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(executed)&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;IllegalStateException(</span><span class="string">"Action&nbsp;has&nbsp;already&nbsp;executed"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;依次调用拦截器堆栈中的拦截器代码执行 </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(interceptors.hasNext())&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">final</span><span>&nbsp;InterceptorMapping&nbsp;interceptor&nbsp;=&nbsp;(InterceptorMapping)&nbsp;interceptors.next(); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.profile(</span><span class="string">"interceptor:&nbsp;"</span><span>+interceptor.getName(),&nbsp; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">new</span><span>&nbsp;UtilTimerStack.ProfilingBlock&lt;String&gt;()&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&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><span class="keyword">public</span><span>&nbsp;String&nbsp;doProfiling()&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&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><span class="comment">//&nbsp;将ActionInvocation作为参数，调用interceptor中的intercept方法执行 </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&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><span class="keyword">this</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>&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><span class="keyword">return</span><span>&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span>
    <li><span>&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>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">else</span><span>&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resultCode&nbsp;=&nbsp;invokeActionOnly(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&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 </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;return&nbsp;above&nbsp;and&nbsp;flow&nbsp;through&nbsp;again </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(!executed)&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;执行PreResultListener </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(preResultListeners&nbsp;!=&nbsp;</span><span class="keyword">null</span><span>)&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">for</span><span>&nbsp;(Iterator&nbsp;iterator&nbsp;=&nbsp;preResultListeners.iterator(); &nbsp;&nbsp;</span></span>
    <li><span>&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;</span>
    <li><span>&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;</span>
    <li><span>&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>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;_profileKey=</span><span class="string">"preResultListener:&nbsp;"</span><span>; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&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;</span>
    <li><span>&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><span class="keyword">this</span><span>,&nbsp;resultCode); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">finally</span><span>&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&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;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;now&nbsp;execute&nbsp;the&nbsp;result,&nbsp;if&nbsp;we're&nbsp;supposed&nbsp;to </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;action与interceptor执行完毕，执行Result </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span>&nbsp;(proxy.getExecuteResult())&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executeResult(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executed&nbsp;=&nbsp;</span><span class="keyword">true</span><span>; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;resultCode; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">finally</span><span>&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UtilTimerStack.pop(profileKey); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">/**
* @throws ConfigurationException If no result can be found with the returned code
*/
public String invoke() throws Exception {
String profileKey = "invoke: ";
try {
UtilTimerStack.push(profileKey);
if (executed) {
throw new IllegalStateException("Action has already executed");
}
// 依次调用拦截器堆栈中的拦截器代码执行
if (interceptors.hasNext()) {
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
UtilTimerStack.profile("interceptor: "+interceptor.getName(),
new UtilTimerStack.ProfilingBlock&lt;String&gt;() {
public String doProfiling() throws Exception {
// 将ActionInvocation作为参数，调用interceptor中的intercept方法执行
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
return null;
}
});
} else {
resultCode = invokeActionOnly();
}
// this is needed because the result will be executed, then control will return to the Interceptor, which will
// return above and flow through again
if (!executed) {
// 执行PreResultListener
if (preResultListeners != null) {
for (Iterator iterator = preResultListeners.iterator();
iterator.hasNext();) {
PreResultListener listener = (PreResultListener) iterator.next();
String _profileKey="preResultListener: ";
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult(this, resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}
// now execute the result, if we're supposed to
// action与interceptor执行完毕，执行Result
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true;
}
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}
</pre>
<br />
<br />
从源码中，我们可以看到，我们之前提到的Struts2的Action层的4个不同的层次，在这个方法中都有体现，他们分别是：拦截器（Interceptor）、Action、PreResultListener和Result。在这个方法中，保证了这些层次的有序调用和执行。由此我们也可以看出<strong><span style="color: red">Struts2在Action层次设计上的众多考虑，每个层次都具备了高度的扩展性和插入点，使得程序员可以在任何喜欢的层次加入自己的实现机制改变Action的行为。</span></strong> <br />
<br />
在这里，需要特别强调的，是其中拦截器部分的执行调用： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>resultCode&nbsp;=&nbsp;interceptor.getInterceptor().intercept(DefaultActionInvocation.</span><span class="keyword">this</span><span>);&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);</pre>
<br />
<br />
表面上，它只是执行了拦截器中的intercept方法，如果我们结合拦截器来看，就能看出点端倪来： <br />
<br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://www.javaeye.com/wiki/struts2/1397-deep-into-struts2-interceptors#"><img alt="复制代码" src="http://www.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">public</span><span>&nbsp;String&nbsp;intercept(ActionInvocation&nbsp;invocation)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Exception&nbsp;{ &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;result&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;before(invocation); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;调用invocation的invoke()方法，在这里形成了递归调用 </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result&nbsp;=&nbsp;invocation.invoke(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;after(invocation,&nbsp;result); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;result; &nbsp;&nbsp;</span></span>
    <li><span>}&nbsp;&nbsp;</span> </li>
</ol>
</div>
<pre class="java" style="display: none" name="code">public String intercept(ActionInvocation invocation) throws Exception {
String result = null;
before(invocation);
// 调用invocation的invoke()方法，在这里形成了递归调用
result = invocation.invoke();
after(invocation, result);
return result;
}</pre>
<br />
<br />
原来在intercept()方法又对ActionInvocation的invoke()方法进行递归调用，ActionInvocation循环嵌套在intercept()中，一直到语句result = invocation.invoke()执行结束。这样，Interceptor又会按照刚开始执行的逆向顺序依次执行结束。 <br />
<br />
<strong><span style="color: red">一个有序链表，通过递归调用，变成了一个堆栈执行过程，将一段有序执行的代码变成了2段执行顺序完全相反的代码过程，从而巧妙地实现了AOP。</span></strong>这也就成为了Struts2的Action层的AOP基础。 </div>
<img src ="http://www.blogjava.net/fantasy/aggbug/257349.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fantasy/" target="_blank">Web 2.0 技术资源</a> 2009-03-02 15:24 <a href="http://www.blogjava.net/fantasy/articles/257349.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转+)Struts2.0 拦截器的实现与定义</title><link>http://www.blogjava.net/fantasy/articles/257311.html</link><dc:creator>Web 2.0 技术资源</dc:creator><author>Web 2.0 技术资源</author><pubDate>Mon, 02 Mar 2009 03:31:00 GMT</pubDate><guid>http://www.blogjava.net/fantasy/articles/257311.html</guid><wfw:comment>http://www.blogjava.net/fantasy/comments/257311.html</wfw:comment><comments>http://www.blogjava.net/fantasy/articles/257311.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/fantasy/comments/commentRss/257311.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fantasy/services/trackbacks/257311.html</trackback:ping><description><![CDATA[<p>转自(http://samyulong.javaeye.com/blog/217092)<br />
<br />
一、<span>什么是拦截器？</span></p>
<p style="text-indent: 21pt"><span>提到拦截器，使我不得不 想起武侠剧中劫匪们常说的一句话：&#8220;此山是我开，此树是我栽，要打此路过，留下买路财！&#8221;。难不成程序中也有&#8220;打劫&#8221;的，说的没错，拦截器就是个打劫的。 在现实生活中，劫匪劫的大都是钱财，当然也有别的什么，那么程序中的&#8220;劫匪&#8221;劫的又是什么呢？或者说程序中为什么需要它？在我们的日常编程中少不了写一些 重复的代码，例如在一个地方中写了一段代码，后来发现这段代码在其它地方中同样需要，在传统的编程中我们一定会采取复制、粘贴的办法。如果这段代码只在这 一两个处需要，我们采取这种办法，还说的过去，但是如果系统对这段代码过于依赖，也就是这段代码在系统中出现的过多，如果那一天我们发现这段代码中在某些 地方还需要完善，我们是不是要着个修改它们呢？我估计没有人会这么做，它严重违反了软件开发中一条非常重要的</span>DRY<span>规则，不写重复代码。说了这么多你一定知道我们为什么需要在程序中弄一个&#8220;劫匪&#8221;了吧。这个&#8220;劫匪&#8221;就是并不是劫取什么东西，只是为了在某个程序执行前后，动态的增加一些功能（以前所写通用代码块）或进行一些检查工作。那么这个拦截器到底是怎么实现的呢？实际上它是用</span>Java<span>中的动态代理来实现的。</span></p>
<p style="margin-left: 21pt; text-indent: -21pt">二、<span>拦截器在</span>Struts2<span>中的应用</span></p>
<p style="text-indent: 21pt"><span>对于</span>Struts2<span>框架而言，正是大量的内置拦截器完成了大部分操作。像</span>params<span>拦截器将</span>http<span>请求中参数解析出来赋值给</span>Action<span>中对应的属性。</span>Servlet-config<span>拦截器负责把请求中</span>HttpServletRequest<span>实例和</span>HttpServletResponse<span>实例传递给</span>Action&#8230;&#8230;struts2<span>内置的拦截器有</span><span>很多，在此我就不一一列举了</span></p>
<p style="text-indent: 21pt"><span>那么怎么在</span>struts2<span>中定义自己的拦截器呢</span>?</p>
<p><span>&nbsp;&nbsp;&nbsp; 很简单</span>Struts2<span>为我们提供了一个</span>Interceptor<span>接口</span>,<span>该接口源代码如下</span>:</p>
<p style="text-align: left" align="left"><strong><span style="font-size: 10pt; color: #7f0055; font-family: &apos">public</span></strong><strong><span style="font-size: 10pt; color: #7f0055; font-family: &apos">interface</span></strong><span style="font-size: 10pt; color: #000000; font-family: &apos"> <span>Interceptor</span> </span><strong><span style="font-size: 10pt; color: #7f0055; font-family: &apos">extends</span></strong><span style="font-size: 10pt; color: #000000; font-family: &apos"> Serializable {</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: #7f0055; font-family: &apos">void</span></strong><span style="font-size: 10pt; color: #000000; font-family: &apos"> destroy();</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp; </span><strong><span style="font-size: 10pt; color: #7f0055; font-family: &apos">void</span></strong><span style="font-size: 10pt; color: #000000; font-family: &apos"> init();</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp; String intercept(ActionInvocation invocation) </span><strong><span style="font-size: 10pt; color: #7f0055; font-family: &apos">throws</span></strong><span style="font-size: 10pt; color: #000000; font-family: &apos"> Exception;</span></p>
<p><span style="font-size: 10pt; color: #000000; font-family: &apos">}</span></p>
<p style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 10pt; color: #000000; font-family: &apos">1)<span style="font-family: &apos">&nbsp;&nbsp;&nbsp; </span></span>init():<span>在拦截器执行之前调用，主要用于初始化系统资源。</span></p>
<p style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 10pt; color: #000000; font-family: &apos">2)<span style="font-family: &apos">&nbsp;&nbsp;&nbsp; </span></span>destroty():<span>与</span>init()<span>对应，用于拦截器执行之后销毁资源。</span></p>
<p style="margin-left: 18pt; text-indent: -18pt"><span style="font-size: 10pt; color: #000000; font-family: &apos">3)<span style="font-family: &apos">&nbsp;&nbsp;&nbsp; </span></span>intercept():<span>拦截器的核心方法，实现具体的拦截操作。与</span>action<span>一样，该方法也返回一个字符串作为逻辑视图。如果拦截器成功调用了</span>action<span>，则返回一个真正的，也就是该</span>action<span>中</span>execute()<span>方法返回的逻辑视图，反之，则返回一个自定义的逻辑视图。</span></p>
<p><span>通常我们使用拦截器并不需要申请资源，为此</span>Struts2<span>还为我们提供了一个</span>AbstractInterceptor<span>类，该类的</span>init()<span>和</span>destroy()<span>都是空实现。我们开发自己的拦截器只需要继承这个类就行了。</span></p>
<p><span>&nbsp;&nbsp;&nbsp; </span><span>下面创建一个判断用户是否登录的拦截器。代码如下</span>:<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; </p>
<div style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 4px; width: 95%; padding-top: 4px">
<div><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.util.Map;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;com.opensymphony.xwork2.Action;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;com.opensymphony.xwork2.ActionInvocation;<br />
</span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;com.opensymphony.xwork2.interceptor.AbstractInterceptor;<br />
<br />
@SuppressWarnings(</span><span style="color: #000000">"</span><span style="color: #000000">serial</span><span style="color: #000000">"</span><span style="color: #000000">)<br />
</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;CheckLoginInterceptor&nbsp;</span><span style="color: #0000ff">extends</span><span style="color: #000000">&nbsp;AbstractInterceptor&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings(</span><span style="color: #000000">"</span><span style="color: #000000">unchecked</span><span style="color: #000000">"</span><span style="color: #000000">)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;String&nbsp;intercept(ActionInvocation&nbsp;actionInvocation)&nbsp;</span><span style="color: #0000ff">throws</span><span style="color: #000000">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">begin&nbsp;check&nbsp;login&nbsp;interceptor!</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;检查Session中是否存在user</span><span style="color: #008000"><br />
</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&nbsp;session&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;actionInvocation.getInvocationContext().getSession();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;username&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(String)&nbsp;session.get(</span><span style="color: #000000">"</span><span style="color: #000000">user</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(username&nbsp;</span><span style="color: #000000">!=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">null</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;username.length()&nbsp;</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">)&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;存在的情况下进行后续操作。</span><span style="color: #008000"><br />
</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">already&nbsp;login!</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;actionInvocation.invoke();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">&nbsp;否则终止后续操作，返回LOGIN</span><span style="color: #008000"><br />
</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000">"</span><span style="color: #000000">no&nbsp;login,&nbsp;forward&nbsp;login&nbsp;page!</span><span style="color: #000000">"</span><span style="color: #000000">);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;Action.LOGIN;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
</div>
&nbsp;&nbsp;&nbsp; 创建好拦截器后，还不能使用，还需要我们在struts.xml<span>中配置一下。</span>
<p>
<p><span>&nbsp; 下面看一下怎么配置拦截器。</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptors</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"checkLogin" </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">class</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"com.myblog.interceptor.CheckLoginInterceptor" </span><span style="font-size: 10pt; color: #008080; font-family: &apos">/&gt;</span></p>
<p><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptors</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p><span>&nbsp;&nbsp; 这个定义好的拦截器在</span>Action<span>中怎么使用呢？使用方法很简单，如下：</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">action </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">" " </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">class</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">" " </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;result&gt; &lt;/result&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-ref </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"checkLogin" </span><span style="font-size: 10pt; color: #008080; font-family: &apos">/&gt;</span></p>
<p><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">action</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p><span>&nbsp;&nbsp; 一旦我们为某个</span>action<span>引用了自定义的拦截器，</span>struts2<span>默认的拦截器就不会再起作用，因此还需要引用默认拦截器。</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">action </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">" " </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">class</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">" " </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;result&gt; &lt;/result&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-ref </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"checkLogin" </span><span style="font-size: 10pt; color: #008080; font-family: &apos">/&gt;</span></p>
<p><span style="color: #008080">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;interceptor-ref name="defaultStack" /&gt;</p>
<p><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">action</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p><span>&nbsp;&nbsp; 但是我们这么做似乎也不太方便，因为如果拦截器</span>checkLogin<span>需要被多个</span>action<span>引用的话，每一个都要配置一遍太麻烦了。我们可以把它定义成默认的拦截器。</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptors</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"checkLogin" </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">class</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"com.myblog.interceptor.CheckLoginInterceptor" </span><span style="font-size: 10pt; color: #008080; font-family: &apos">/&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #008080; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!—-</span><span>定义一个拦截器栈</span><span style="font-size: 10pt; color: #008080; font-family: &apos">--&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-stack </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"mydefault"</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-ref </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"defaultStack" </span><span style="font-size: 10pt; color: #008080; font-family: &apos">/&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-ref </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"checkLogin" </span><span style="font-size: 10pt; color: #008080; font-family: &apos">/&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-stack</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptors</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">default-interceptor-ref </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"mydefault" </span><span style="font-size: 10pt; color: #008080; font-family: &apos">/&gt;</span></p>
<p><span>&nbsp;&nbsp; 另外，</span>struts2<span>还为我们提供了一个方法过滤的拦截器</span>MethodFilterInterceptor<span>类，该类继承</span>AbstractInterceptor<span>类，重写了</span><span style="font-size: 10pt; color: #000000; font-family: &apos">intercept(ActionInvocation invocation)</span><span>并提供了一个新的方法</span><span style="font-size: 10pt; color: #000000; font-family: &apos">doInterceptor(ActionInvocation invocation)</span><span>抽象方法。该类的使用方法很简单，就不举例了。这个拦截器与以往的拦截器配置有所不同。那就是可以指定哪些方法需要被拦截，那些不需要。通常在引用该拦截器时指定。</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-ref </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">" &nbsp;"</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">param </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"exculdeMethods"</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">param</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p style="text-align: left" align="left"><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">param </span><span style="font-size: 10pt; color: #7f007f; font-family: &apos">name</span><span style="font-size: 10pt; color: #000000; font-family: &apos">=</span><span style="font-size: 10pt; color: #2a00ff; font-family: &apos">"includeMethods"</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">param</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span><span style="font-size: 10pt; color: #000000; font-family: &apos">&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span style="font-size: 10pt; color: #008080; font-family: &apos">&lt;/</span><span style="font-size: 10pt; color: #3f7f7f; font-family: &apos">interceptor-ref</span><span style="font-size: 10pt; color: #008080; font-family: &apos">&gt;</span></p>
<p>&nbsp;&nbsp; exculdeMethods<span>：是不被拦截的方法，如果有多个以逗号分隔。</span></p>
<p>&nbsp;&nbsp; includeMethods<span>：需要被拦截的方法，如果有多个以逗号分隔。</span></p>
<p>&nbsp;</p>
<hr style="width: 100%; height: 2px" />
<p><span><br />
&nbsp;&nbsp;&nbsp; 下面我来实验下。我们写个拦截器栈<br />
&nbsp;&nbsp;&nbsp; </span></p>
<div style="padding-right: 5.4pt; padding-left: 5.4pt; padding-bottom: 4px; width: 95%; padding-top: 4px">
<div><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptors</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="authorize"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="com.struts2.interceptor.AuthorizeInterceptor"</span><span style="color: #ff0000">&nbsp;</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-stack&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="appStack"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">&lt;!--</span><span style="color: #008000">&nbsp;你自定义的&nbsp;</span><span style="color: #008000">--&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="authorize"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">&lt;!--</span><span style="color: #008000">&nbsp;系统内置的拦截器栈&nbsp;</span><span style="color: #008000">--&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="defaultStack"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptor-stack</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">interceptors</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">action&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="forward"</span><span style="color: #ff0000">&nbsp;class</span><span style="color: #0000ff">="com.struts2.RequestForward"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">interceptor-ref&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="appStack"</span><span style="color: #0000ff">/&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="index"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">index.jsp</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">result</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">&lt;</span><span style="color: #800000">result&nbsp;</span><span style="color: #ff0000">name</span><span style="color: #0000ff">="NOT_FOUND"</span><span style="color: #0000ff">&gt;</span><span style="color: #000000">not_found.jsp</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">result</span><span style="color: #0000ff">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #0000ff">&lt;/</span><span style="color: #800000">action</span><span style="color: #0000ff">&gt;</span></div>
</div>
&nbsp;&nbsp;&nbsp; 恩，还是有点很迷茫的位置，比说的拦截器的调用顺序是根据xml里面的顺序来的吗？还有可以指定只在action之前或者只在action之后调用吗？说实话我也搞不清楚，在运用的过程中，大家慢慢在来体会<br />
<br />
<br />
<p>拦截器几乎完成了Struts2框架70%的工作，包括解析请求参数、将请求参数赋值给Action属性、执行数据校验、文件上传&#8230;&#8230;，Struts2设计的灵巧性，更大程度地得益于拦截器设计，当需要扩展Struts2功能时，只需要提供对应拦截器，并将它配置在Struts2容器中即可；如果不需要该功能时，也只需要取消该拦截器的配置即可。这种可插拔式的设计，正是软件设计领域一直孜孜以求的目标。</p>
<p>实际上，Struts2的精髓就在于拦截器，掌握了Struts2的拦截器机制，你就可以说精通了Struts2。<br />
从某个角度来看，我们可以把Struts2框架理解成一个空壳，而这些拦截器像一个一个抽屉，随时可以<br />
插进入，也可以拔出来——这是软件产品一直追求的目标。<br />
如果你喜欢，你可以把Struts2的全部插件拔出，那么Struts2就成了一个空容器——<br />
而这种空，正是 Struts2的魅力，你可以把任何自己想要的东西填入进去，甚至包括自己完全实现这个框架。</p>
<p>另一方面，因为Struts2的插件机制,Struts2提供了无限扩展的可能性，你可以把自己想要的任何<br />
东西做成插件，然后填入Struts2——这样的结果是：一个企业，一个团队，可以把自己业务相关的东西<br />
做成插件，随时随地地复用。<br />
也就是说：如果你想要，你可以把Struts2改造成属于自己的框架。</p>
<p>当然，Struts2也内建了大量的拦截器，这些拦截器以name-class对的形式配置在struts-default. xml文件中，其中name是拦截器的名字，就是以后使用该拦截器的唯一标识；class则指定了该拦截器的实现类，如果我们定义的package继承了Struts2的默认struts-default包，则可以自由使用下面定义的拦截器，否则必须自己定义这些拦截器。<br />
下面是Struts2内建拦截器的简要介绍：<br />
alias：实现在不同请求中相似参数别名的转换。<br />
autowiring：这是个自动装配的拦截器，主要用于当Struts2和Spring整合时，Struts2可以使用自动装配的方式来访问Spring容器中的Bean。<br />
chain：构建一个Action链，使当前Action可以访问前一个Action的属性，一般和&lt;result type="chain" .../&gt;一起使用。<br />
conversionError：这是一个负责处理类型转换错误的拦截器，它负责将类型转换错误从ActionContext中取出，并转换成Action的FieldError错误。<br />
createSession：该拦截器负责创建一个HttpSession对象，主要用于那些需要有HttpSession对象才能正常工作的拦截器中。<br />
debugging：当使用Struts2的开发模式时，这个拦截器会提供更多的调试信息。<br />
execAndWait：后台执行Action，负责将等待画面发送给用户。<br />
exception：这个拦截器负责处理异常，它将异常映射为结果。<br />
fileUpload：这个拦截器主要用于文件上传，它负责解析表单中文件域的内容。 <br />
i18n：这是支持国际化的拦截器，它负责把所选的语言、区域放入用户Session中。<br />
logger：这是一个负责日志记录的拦截器，主要是输出Action的名字。<br />
model-driven：这是一个用于模型驱动的拦截器，当某个Action类实现了ModelDriven接口时，它负责把getModel()方法的结果堆入ValueStack中。 <br />
scoped-model-driven：如果一个Action实现了一个ScopedModelDriven接口，该拦截器负责从指定生存范围中找出指定的Modol，并将通过setModel方法将该Model传给Action实例。<br />
params：这是最基本的一个拦截器，它负责解析HTTP请求中的参数，并将参数值设置成Action对应的属性值。<br />
prepare：如果action实现了Preparable接口，将会调用该拦截器的prepare()方法。<br />
static-params：这个拦截器负责将xml中&lt;action&gt;标签下&lt;param&gt;标签中的参数传入action。<br />
scope：这是范围转换拦截器，它可以将Action状态信息保存到HttpSession范围，或者保存到ServletContext范围内。<br />
servlet-config：如果某个Action需要直接访问Servlet API，就是通过这个拦截器实现的。<br />
注意：尽量避免在Action中直接访问Servlet API，这样会导致Action与Servlet的高耦合。<br />
roles：这是一个JAAS（Java Authentication and Authorization Service，Java授权和认证服务）拦截器，只有当浏览者取得合适的授权后，才可以调用被该拦截器拦截的Action。<br />
timer：这个拦截器负责输出Action的执行时间，这个拦截器在分析该Action的性能瓶颈时比较有用。<br />
token：这个拦截器主要用于阻止重复提交，它检查传到Action中的token，从而防止多次提交。<br />
token-session：这个拦截器的作用与前一个基本类似，只是它把token保存在HttpSession中。<br />
validation：通过执行在xxxAction-validation.xml中定义的校验器，从而完成数据校验。<br />
workflow：这个拦截器负责调用Action类中的validate方法，如果校验失败，则返回input的逻辑视图。<br />
大部分时候，开发者无需手动控制这些拦截器，因为struts-default.xml文件中已经配置了这些拦截器，只要我们定义的包继承了系统的struts-default包，就可以直接使用这些拦截器。</p>
<p>当然，Struts2的拦截器机制并不是来自于Struts1，而是来自于WebWork。</p>
<br />
<img src ="http://www.blogjava.net/fantasy/aggbug/257311.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fantasy/" target="_blank">Web 2.0 技术资源</a> 2009-03-02 11:31 <a href="http://www.blogjava.net/fantasy/articles/257311.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>