java 设计模式 拦截器

拦截器(interceptor)是Struts2最强大的特性之一,也可以说是struts2的核心,拦截器可以让你在Action和result被执行之前或之后进行一些处理。同时,拦截器也可以让你将通用的代码模块化并作为可重用的类。Struts2中的很多特性都是由拦截器来完成的。拦截是AOP的一种实现策略。在Webwork的中文文档的解释为:拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor
Chain,在Struts 2中称为拦截器栈Interceptor
Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用

为了便于自身理解,我们自己实现一个。
在我们的请求到来之前,加入现在我进入了一个页面,而改页面是需要先检查是否已登录,此时如果我加一个判断的话,就可以很容易实现,但是当我们的页面增多时,那么就该为我们的每个请求页面都加个判断,是相当麻烦的一件事,故此,spring或struts都为我们提供了相应的拦截器,以下是拦截器的实现原理:
这里写图片描述

首先我们需要定义一个action接口

public interface Action {
    String execute();
}

拦截器接口

public interface Interceptor {  
    void before(ActionInvocation invocation);
    String intercept(ActionInvocation invocation);
    void after(ActionInvocation invocation);
}

调度器接口

public interface ActionInvocation {
    String invoke();
}

定义我们的拦截器

AroundInterceptor 拦截器

package com.cmh.intercept;

import com.cmh.service.ActionInvocation;

public class AroundInterceptor implements Interceptor{

    @Override
    public void before(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("before:"+"AroundInterceptor");
    }

    @Override
    public String intercept(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        before(invocation);
        String result = invocation.invoke();
        after(invocation);
        return result;
    }

    @Override
    public void after(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("after:"+"AroundInterceptor");
    }
}

ExceptionInterceptor拦截器

package com.cmh.intercept;

import com.cmh.service.ActionInvocation;

public class ExceptionInterceptor implements Interceptor{

    @Override
    public void before(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("before:"+"ExceptionInterceptor");
    }

    @Override
    public String intercept(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        before(invocation);
        String result = invocation.invoke();
        after(invocation);
        return result;
    }

    @Override
    public void after(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("after:"+"ExceptionInterceptor");
    }
}

I18NInterceptor拦截器

package com.cmh.intercept;

import com.cmh.service.ActionInvocation;

public class I18NInterceptor implements Interceptor{

    @Override
    public void before(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("before:"+"I18NInterceptor");
    }

    @Override
    public String intercept(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        before(invocation);
        String result = invocation.invoke();
        after(invocation);
        return result;
    }

    @Override
    public void after(ActionInvocation invocation) {
        // TODO Auto-generated method stub
        System.out.println("after:"+"I18NInterceptor");
    }
}

调度器实现类DefaultActionInvoation

package com.cmh.service;

import java.util.ArrayList;
import java.util.List;

import com.cmh.action.Action;
import com.cmh.intercept.Interceptor;

public class DefaultActionInvoation implements ActionInvocation{

    int index = 0;

    private Action action; 

    private List<Interceptor> interceptors = new ArrayList<Interceptor>();



    /**
     * Get action   
     * @return Action the action
     */
    public Action getAction() {
        return action;
    }

    /**
     * Set action
     * @param action Action the action to set
     */
    public void setAction(Action action) {
        this.action = action;
    }


    /**
     * Set interceptors
     * @param interceptors List<Interceptor> the interceptors to set
     */
    public void addInterceptor(Interceptor interceptors) {
        this.interceptors.add(interceptors);
    }



    @Override
    public String invoke() {//递归调用
        // TODO Auto-generated method stub
        String result = ""; 
        if(index == interceptors.size()){
            result = action.execute();
        }else{
            Interceptor interceptor =interceptors.get(index);
            index++;
            result = interceptor.intercept(this);
        }
        return result;
    }

}

测试类

public static void test3(){
        Interceptor exptionInterceptor = new ExceptionInterceptor();  
        Interceptor i18nInterceptor = new I18NInterceptor();  
        Interceptor aroundInterceptor = new AroundInterceptor();  

        DefaultActionInvoation actionInvocation = new DefaultActionInvoation();  
        actionInvocation.addInterceptor(exptionInterceptor);  
        actionInvocation.addInterceptor(i18nInterceptor);  
        actionInvocation.addInterceptor(aroundInterceptor);  


        Action action = new HelloWorldAction();  
        actionInvocation.setAction(action);  

        String result = actionInvocation.invoke();  
        System.out.println("Action result:" + result); 
    }

测试结果
这里写图片描述

由以上代码不难看出,当我们的请求来到时,首先会经DefaultActionInvoation 的invoke处理,调用的次序依次为
ExceptionInterceptor->I18NInterceptor->AroundInterceptor->AroundInterceptor->I18NInterceptor->ExceptionInterceptor
最后才将我们的结果给弄出来,以上为一个拦截器最基本的原理。下面我们来看看struts2中的原代码及流程

strtus2的流程图
这里写图片描述

我们再来看看他的源代码

以下是DefaultActionInvoation 中的invoke的源代码

/** 

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

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

    }  

}  

拦截器的源代码

public String intercept(ActionInvocation invocation) throws Exception {  

String result = null;  


        before(invocation);  

        // 调用下一个拦截器,如果拦截器不存在,则执行Action  

        result = invocation.invoke();  

        after(invocation, result);  


        return result;  

}  

struts的拦截器最大归功于他的动态代理模式,因为我们的action具体类都是一个继承动态代理的类。所以这就不必为每一个类都加相应的逻辑,只需继承就行了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值