structs2拦截器.docx
《structs2拦截器.docx》由会员分享,可在线阅读,更多相关《structs2拦截器.docx(17页珍藏版)》请在冰豆网上搜索。
structs2拦截器
什么是Struts 2拦截器?
从软件构架上来说,拦截器是实现了面向方面编程的组件。
它将影响了多个业务对象的公共行为封装到一个个可重用的模块,减少了系统的重复代码,实现功能的高度内聚,确保了业务对象的整洁和纯度。
从Java代码上来说,它就是一个普度的Java对象,它只需要实现一个名为Interceptor的接口。
为什么要使用拦截器?
拦截器消除了动作组件中的横切任务(cross-cuttingtask)。
例如,日志记录是一个典型的横切关注。
以前,我们可能需要为每个动作组件准备一些记录日志的代码。
虽然这样看上去也没什么错误,但是一个不可以忽视的事实是——这些用于记录日志的代码并不是动作组件与模型交互的一部分。
并且,日志记录是我们想为系统处理的每一个请求完成的管理性任务,它不是一个动作组件所特有的,而是贯穿了所有动作组件。
Struts2将这个功能放在了更高的层次上,我们可以能把日志记录的代码转移到动作组件之外,从而让动作组件更加简洁清晰。
拦截器组件提供了一个不错的场所,来将不同的横切关注点逻辑分成有层次的、可重用的部件。
拦截器的工作原理?
当框架接收到一个请求的时候,它首先必须决定这个URL映射到哪一个动作组件。
这个动作组件的一个实例就会被加入到一个新创建的ActionInvocation实例中。
接着框架咨询声明性架构(XML配置文件或Java注解),以发现哪一些拦截器应该被触发,以及按照什么样的顺序触发。
将这些拦截器的引用添加到ActionInvocation中。
除了这些核心元素,ActionInvocation也拥有其他重要的信息(Servlet请求对象和当前动作组件可用的结果组件列表)。
当ActionInvocation被创建完毕,并且填充了需要的所有对象和信息,就可以被使用了。
ActionInvocation公开了一个invoke()方法,框架通过调用这个方法开始动作的执行。
当框架调用了这个方法时,ActionInvocation通过执行拦截器栈中的第一个拦截器开始这个调用过程。
需要注意的是,invoke()并不是总是指向拦截器栈的第一个拦截器,ActionInvocation负责跟踪执行过程达到的状态,并且把控制交给栈中合适的拦截器(通过调用拦截器的intercept()方法将控制权交给拦截器)。
通过递归调用(递归过程?
框架通过第一次调用ActionInvocation对象的invoke()方法开始了这个过程。
ActionInvocation通过调用拦截器的intercept()方法把控制权交给第一个拦截器。
重要的是,intercept()方法把ActionInvocation实例作为一个参数。
在拦截器的处理过程中,他会调用ActionInvocation实例参数的invoke()方法来继续调用后续拦截器的递归过程。
因此,在通常的执行中,调用过程向下通过所有拦截器,直到栈中再也没有拦截器时,触发动作。
另外,ActionInvocation在内部管理处理状态,因此它总是直到自己现在处在栈的什么位置。
)ActionInvocation的invoke()方法,拦截器栈中后续的拦截器继续执行,最终执行动作。
这是因为每一次invoke()方法被调用时,ActionInvocation都会查询自身的状态,调用接下来的拦截器。
在所有拦截器都被调用之后,invoke()方法会促使动作类执行。
下面看一个简单的例子,演示上面所说的理论:
TestAction
publicclassTestActionextendsActionSupport
{
privatestaticfinallongserialVersionUID=2753590609366162370L;
@Override
publicStringexecute()throwsException
{
System.out.println("execute");
returnSUCCESS;
}
}
Interceptor1
publicclassIntercept1implementsInterceptor
{
privatestaticfinallongserialVersionUID=8596224826058233434L;
publicvoiddestroy()
{
}
publicvoidinit()
{
}
publicStringintercept(ActionInvocationinvocation)throwsException
{
System.out.println("interceptor1begin");
Stringresult=invocation.invoke();
System.out.println("interceptor1end");
returnresult;
}
}
Interceptor2
publicclassIntercept2implementsInterceptor
{
privatestaticfinallongserialVersionUID=-1580591331691823185L;
publicvoiddestroy()
{
}
publicvoidinit()
{
}
publicStringintercept(ActionInvocationinvocation)throwsException
{
System.out.println("interceptor2begin");
Stringresult=invocation.invoke();
System.out.println("interceptor2end");
returnresult;
}
}
Interceptor3
publicclassIntercept3implementsInterceptor
{
privatestaticfinallongserialVersionUID=7081124564804422023L;
publicvoiddestroy()
{
}
publicvoidinit()
{
}
publicStringintercept(ActionInvocationinvocation)throwsException
{
System.out.println("interceptor3begin");
Stringresult=invocation.invoke();
System.out.println("interceptor3end");
returnresult;
}
}
有三个自定以的拦截器,他们只是简单的输出几个字符串,拦截器开始将执行输出"interceptor'x'begin";拦截器结束时输出"interceptor'x'end";
将他们设置在一个指定的动作上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15/index.jsp
16
17
提交表单,控制台的输出结果:
interceptor1begin
interceptor2begin
interceptor3begin
execute
interceptor3end
interceptor2end
interceptor1end
从控制台输出的结果可以看出,在提交数据到框架时,框架调用拦截器的过程,首先框架会根据URL请求创建指定的动作TestAction,将TestAction的实例和TestAction相关的拦截器引用myStack放入一个新的ActionInvocation对象中(还包含其他信息),然后框架调用ActionInvocation的invoke()方法,此时开始了拦截器栈调用过程,最开始调用拦截器栈的第一个拦截器也就是Intercept1,拦截器执行完预处理后,因为intercept()方法接收一个ActionInvocation对象作为参数,在Intercept1.intercept()方法中继续调用ActionInvocation对象的invoke()方法将向下继续调用栈中余下的拦截器Intercept2...一直到栈中没有拦截器为止,最后执行动作组件。
在结果被呈现之后,拦截器会按照相反的顺序再触发一遍,使他们可以进行后处理。
拦截器工作原理图:
拦截器触发时能够做些什么?
1.做一些预处理。
在这个阶段拦截器可以用来准备、过滤、改变或者操作任何可以访问的重要数据。
这些数据包括所有与当前请求相关的关键对象和数据,也包括动作。
2.通过调用invoke()方法将控制转移给后续的拦截器,直到动作。
或者通过返回一个控制字符串中断执行。
在这个阶段,如果拦截器决定请求不应该继续,他可以不调用ActionInvocation实例上的invoke()方法,而是直接返回一个控制字符串。
通过这种方式可以停止后续的执行,并且决定哪个结果被呈现。
3.做一些后加工。
在这个阶段,任何一个返回的拦截器可以修改可以访问的对象的数据作为后加工,但是此时结果已经确定了。
怎么声明拦截器?
下面为Struts2为我们提供的struts-default.xml文件部分:
...
--Basicstack-->
dojo\..*,^struts\..*
--Samplevalidationandworkflowstack-->
--SampleJSONvalidationstack-->
input,back,cancel
--Samplefileuploadstack-->
--Samplemodel-drivenstack-->
--Sampleactionchainingstack-->
--Sample