快捷搜索:  as  2018  FtCWSyGV  С˵  test  xxx  Ψһ  w3viyKQx

葡京娱乐场娱乐网址_龟发之家论坛



接下来,我们将重点评论争论一下Struts2中的拦截器的内部布局和履行顺序,并结合源码进行阐发。

目 录

Interceptor布局

Interceptor履行阐发

源码解析

Interceptor布局

让我们再往返首一下之前我们曾经用过的一张Action LifeCycle的图:

图中,我们可以发明,Struts2的Interceptor一层一层,把Action包裹在最里面。这样的布局,大年夜概有以下一些特征:

1. 全部布局就犹如一个客栈,除了Action以外,客栈中的其他元素是Interceptor

2. Action位于客栈的底部。因为客栈"先辈后出"的特点,假如我们试图把Action拿出来履行,我们必须首先把位于Action上真个Interceptor拿出来履行。这样,全部履行就形成了一个递归调用

3. 每个位于客栈中的Interceptor,除了必要完成它自身的逻辑,还必要完成一个特殊的履行职责。这个履行职责有3种选择:

1) 中止全部履行,直接返回一个字符串作为resultCode

2) 经由过程递归调用认真调用客栈中下一个Interceptor的履行

3) 假如在客栈内已经不存在任何的Interceptor,调用Action

Struts2的拦截器布局的设计,实际上是一个范例的责任链模式的利用。首先将全部履行划分成多少相同类型的元素,每个元素具备不合的逻辑责任,并将他们纳入到一个链式的数据布局中(我们可以把客栈布局也看作是一个递归的链式布局),而每个元素又有责任认真链式布局中下一个元素的履行调用。

这样的设计,从代码重构的角度来看,实际上是将一个繁杂的系统,分而治之,从而使得每个部分的逻辑能够高度重用并具备高度可扩展性。以是,Interceptor布局其实是Struts2/Xwork设计中的英华之笔。

Interceptor履行阐发

Interceptor的定义

我们来看一下Interceptor的接口的定义:

Java代码

public interface Interceptor extends Serializable {

/**

* Called to let an interceptor clean up any resources it has allocated.

*/

void destroy()葡京娱乐场娱乐网址;

/**

* Called after an int葡京娱乐场娱乐网址erceptor 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;

}

Interceptor的接口定义没有什么特其余地方,除了init和destory措施以外,intercept措施是实现全部拦截器机制的核心措施。而它所依附的参数ActionInvocation则是我们之前章节中曾经提到过的闻名的Action调整者。

我们再来看看一个范例的Interceptor的抽象实现类:

2. 我们可以以invocation.invoke()为界,将拦截器中的代码分成2个部分,在invocation.invoke()之前的代码,将会在Action之前被依次履行,而在invocation.invoke()之后的代码,将会在Action之后被逆序履行。

由此,我们就可以经由过程invocation.invoke()作为Action代码真正的拦截点,从而实现AOP。

Interceptor拦截类型

从上面的阐发,我们知道,全部拦截器的核心部分是invocation.invoke()这个函数的调葡京娱乐场娱乐网址用位置。事实上,我们也正式根据这句代码的调用位置,来进行拦截类型的区分的。在Struts2中,Interceptor的拦截类型,分成以下三类:

1. before

before拦截,是指在葡京娱乐场娱乐网址拦截器中定义的代码,它们存在于invocation.invoke()代码履行之前。这些代码,将依照拦截器定义的顺序,顺序履行。

2. after

after拦截,是指在拦截器中定义的代码,它们存在于invocation.invoke()代码履行之后。这些代码,将一招拦截器定义的顺序,逆序履行。

3. PreResultListener

有的时刻,before拦截和after拦截对我们来说是不敷的,由于我们必要在Action履行完之后,然则还没有回到视图层之前,做一些工作。Struts2同样支持这样的拦截,这种拦截要领,是经由过程在拦截器中注册一个PreResultListener的接口来实现的。

Java代码

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);

}

  图片看不清楚?请点击这里查看原图(大年夜图)。

在这里,我轻细改了一下Struts2的Reference中的履行顺序示例,使得全部履行顺序加倍能够被理解。我们可以看到,递归调用包管了各类各样的拦截类型的履行能够有条不紊。

请留意在这里,每个拦截器中的代码的履行顺序,在Action之前,拦截器的履行顺序与客栈中定义的同等;而在Action和Result之后,拦截器的履行顺序与客栈中定义的顺序相反。

源码解析

接下来我们就来看看源码,看看Struts2是若何包管拦截器、Action与Result三者之间的履行顺序的。

之前我曾经提到,ActionInvocation是Struts2中的调整器,以是事实上,这些代码的调整履行,是在ActionInvocation的实现类中完成的,这里,我抽取了DefaultActionInvocation中的invoke()措施,它将向我们展示统统。

Java代码

/**

* @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() {

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 retu葡京娱乐场娱乐网址rn 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);

}

}

您可能还会对下面的文章感兴趣: