posts - 431,  comments - 344,  trackbacks - 0
WebWork 教程 - Interceptor( 拦截器 )
Interceptor (拦截器)将 Action 共用的行为独立出来,在 Action 执行前后运行。这也就是我们所说的 AOP ( Aspect Oriented Programming ,面向切面编程),它是分散关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
 
Interceptor 将很多功能从我们的 Action 中独立出来,大量减少了我们 Action 的代码,独立出来的行为具有很好的重用性。 XWork 、 WebWork 的许多功能都是有 Interceptor 实现,可以在配置文件中组装 Action 用到的 Interceptor ,它会按照你指定的顺序,在 Action 执行前后运行。 Interceptor 在框架中的应用如下图所示
 
 
当你提交对 Aciton (默认是 .action 结尾的 Url )的请求时, ServletDispatcher 会根据你的请求,去调度并执行相应的 Action 。在 Action 执行之前,调用被 Interceptor 截取, Interceptor 在 Action 执行前后运行。
 
我们在用户注册的例子中就使用了取得 Request 请求参数的拦截器,配置文件中 <interceptor-ref name="params"/> 将拦截器 params 组装到 RegisterAction 中。“ params ”在我们的 webwork-default.xml 配置文件中有定义, webwork-default.xml 中拦截器的定义如下:
 
<interceptors>
            <interceptor name="timer" class="com.opensymphony.xwork.interceptor.TimerInterceptor"/>
            <interceptor name="logger" class="com.opensymphony.xwork.interceptor.LoggingInterceptor"/>
            <interceptor name="chain" class="com.opensymphony.xwork.interceptor.ChainingInterceptor"/>
            <interceptor name="static-params" class="com.opensymphony.xwork.interceptor.StaticParametersInterceptor"/>
            <interceptor name="params" class="com.opensymphony.xwork.interceptor.ParametersInterceptor"/>
            <interceptor name="model-driven" class="com.opensymphony.xwork.interceptor.ModelDrivenInterceptor"/>
            <interceptor name="component" class="com.opensymphony.xwork.interceptor.component.ComponentInterceptor"/>
            <interceptor name="token" class="com.opensymphony.webwork.interceptor.TokenInterceptor"/>
            <interceptor name="token-session" class="com.opensymphony.webwork.interceptor.TokenSessionStoreInterceptor"/>
            <interceptor name="validation" class="com.opensymphony.xwork.validator.ValidationInterceptor"/>
            <interceptor name="workflow" class="com.opensymphony.xwork.interceptor.DefaultWorkflowInterceptor"/>
            <interceptor name="servlet-config" class="com.opensymphony.webwork.interceptor.ServletConfigInterceptor"/>
            <interceptor name="prepare" class="com.opensymphony.xwork.interceptor.PrepareInterceptor"/>
            <interceptor name="conversionError" class="com.opensymphony.webwork.interceptor.WebWorkConversionErrorInterceptor"/>
            <interceptor-stack name="defaultStack">
                <interceptor-ref name="static-params"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
            </interceptor-stack>
            <interceptor-stack name="validationWorkflowStack">
                <interceptor-ref name="defaultStack"/>
                <interceptor-ref name="validation"/>
                <interceptor-ref name="workflow"/>
            </interceptor-stack>
        </interceptors>
这些都时有框架提供的默认的 Interceptor ,下面我来看看 Interceptor 使用的步骤:
1、   创建一个自己需要的 Interceptor 类,它必需实现
com.opensymphony.xwork.interceptor.Interceptor
接口,具体的开发见下面的 Interceptor 的原理。
2、   在配置文件( xwork..xml )中申明这个 Interceptor 类,它放在标签 <interceptor /> 中,同是 <interceptor /> 标签嵌入在 <interceptors /> 标签内部。
3、   创建 Interceptor 栈,使用标签: <interceptor-stack /> , 让一组 Interceptor 可以按次序调用。(可选)
4、   指定 Action 所要用到的 Interceptor (前面申明过的),可以用 <interceptor-ref /> 或 <default-interceptor-ref /> 标签。前面的标签指定某个 Action 所用到的 Interceptor ,如果 Action 没有被用 <interceptor-ref /> 指定 Interceptor ,它将使用 <default-interceptor-ref /> 指定的 Interceptor 。
框架中给我们提供了很多实用的 Interceptor ,它的定义上面已经给出,它的具体功能如下:
l          timer :记录 Action 执行的时间,并做为日志信息输出;
l          logger :在日志信息中输出要执行的 Action 信息;
l          chain :将前一个执行结束的 Action 属性设置到当前的 Action 中。它被用在 ResultType 为“ chain ”指定结果的 Action 中,该结果 Action 对象会从 OgnlValueStack 中获得前一个 Action 对应的属性,它实现 Action 链之间的数据传递;
l          static-params :将 xwork.xml 配置文件里定义的 Action 参数,设置到对应的 Action 中。 Action 参数使用 <param /> 标签,是 <action /> 标签的直接子元素。我们这里定义的 Action 类必需实现 com.opensymphony.xwork.config.entities . Parameterizable 接口;
l          params :将 Request 请求的参数设置到相应 Action 对象的属性中,用户注册例子用到过这个拦截器;
l          model-driven :如果 Action 实现 ModelDriven 接口,它将 getModel() 取得的模型对象存入 OgnlValueStack 中;
l          component :激活组件功能支持,让注册过的组件在当前 Action 中可用,即为 Action 提供 IoC (依赖倒转控制)框架的支持;
l          token :核对当前 Action 请求( request )的有效标识,防止重复提交 Action 请求 (request) 。
l          token-session :功能同上,但是当提交无效的 Action 请求标识时,它会将请求数据保存到 session 中。
l          validation :实现使用 xml 配置文件( {Action}-validation.xml )对 Action 属性值进行验证,详细请看后面介绍的验证框架。
l          workflow :调用 Action 类的验证功能,假设 Action 使用 ValidationAware 实现验证( ActionSupport 提供此功能),如果验证没有通过, workflow 会将请求返回到 input 视图( Action 的 <result /> 中定义的)。
l          servlet-config :提供 Action 直接对 HttpServletRequest 或 HttpServletResponse 等 JavaServlet api 的访问, Action 要实现相应的接口,例如: ServletRequestAware 或 ServletResponseAware 等 。如果必需要提供对 JavaServlet api 的访问,我们建议使用 ServletActionContext ,在前面 ActionContext 章节中有介绍。
l          prepare :在 Action 执行之前调用 Action 的 prepare() 方法,这个方法是用来准备 Action 执行之前要做的工作。它要求我们的 Action 必需实现 com.opensymphony.xwork . Preparable 接口
conversionError :用来处理框架进行类型转化 (Type Conversion) 时的出错信息。它将存储在 ActionContext 中的类型转化( Type Conversion )错误信息转化成相应的 Action 字段的错误信息,保存在堆栈中。根据需要,可以将这些错误信息在视图中显示出来。
 
Interceptor 的原理
下面我们来看看 Interceptor 是如何实现在 Action 执行前后调用的:
Action 和 Interceptor 在框架中的执行,是由 ActionInvocation 对象调用的。它是用方法: String invoke() throws Exception; 来实现的,它首先会依次调用 Action 对应的 Interceptor ,执行完成所有的 Interceptor 之后,再去调用 Action 的方法,代码如下:
if (interceptors.hasNext()) {
Interceptor interceptor = (Interceptor) interceptors.next();
resultCode = interceptor.intercept(this);
} else {
     if (proxy.getConfig().getMethodName() == null) {
resultCode = getAction().execute();
} else {
        resultCode = invokeAction(getAction(), proxy.getConfig());
}
}
它会在拦截器栈中遍历 Interceptor ,调用 Interceptor 的 方法:
String intercept(ActionInvocation invocation) throws Exception; 。
我们一直都提到, Interceptor 是在 Action 前后执行,可是从上面的代码我们看到的却是执行完所有 Interceptor 的 intercept () 方法之后再去调用我们的 Action 。“在 Action 前后执行”是如何实现的呢?我们来看看抽象类 AroundInterceptor 的 intercept () 实现:
public String intercept(ActionInvocation invocation) throws Exception {
        String result = null;
 
        before(invocation);
        result = invocation.invoke();
        after(invocation, result);
 
        return result;
    }
原来在 intercept () 方法又对 ActionInvocation 的 invoke() 方法进行递归调用, ActionInvocation 循环嵌套在 intercept () 中,一直到语句 result = invocation.invoke(); 执行结束,即: Action 执行完并返回结果 result ,这时 Interceptor 对象会按照刚开始执行的逆向顺序依次执行结束。这样 before () 方法将在 Action 执行前调用, after () 方法在 Action 执行之后运行
posted on 2006-12-14 19:16 周锐 阅读(733) 评论(0)  编辑  收藏 所属分类: Webwork