Struts2拦截器源码分析

当一个请求发出时,由StrutsPrepareAndExecuteFilter过滤请求。它会调用Dispatcher来处理请求,Dispatcher类会执行serviceAction方法,创建ActionProxy,并调用ActionProxy的execute()方法。ActionProxy的execute()方法会调用ActionInvocation的invoke()方法。

public String invoke() throws Exception {
     String profileKey = "invoke: ";
     try {
         UtilTimerStack.push(profileKey);
         if (executed) {
             throw new IllegalStateException("Action has already executed");
         }
         if (interceptors.hasNext()) { //1判断拦截器链是否有下一个
             //2
             final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
             String interceptorMsg = "interceptor: " + interceptor.getName();
             UtilTimerStack.push(interceptorMsg);
             try {
                resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);  // 3调用拦截器intercept方法,并把当前引用传给拦截器
             }finally {
                UtilTimerStack.pop(interceptorMsg);
             }
         } else {
             resultCode = invokeActionOnly();  // 4当拦截器链中不存在下一个拦截器时,调用action
         }
         if (!executed) { // 5如果没有执行过拦截器或action的结果
             if (preResultListeners != null) { // 6如果有前置结果监听器则,则在结果执行前调用
                for (Object preResultListener : preResultListeners) {
                   PreResultListener listener = (PreResultListener) preResultListener;
                   String _profileKey = "preResultListener: ";
                   try {
                       UtilTimerStack.push(_profileKey);
                       listener.beforeResult(this, resultCode);
                   }finally {
                       UtilTimerStack.pop(_profileKey);
                   }
                }
             }
             // now execute the result, if we're supposed to
             if (proxy.getExecuteResult()) {
                 executeResult();  // 7执行结果
             }
             executed = true; // 8执行标志改为true
         }
         return resultCode; // 9
     } finally {
         UtilTimerStack.pop(profileKey);
     }
 }
 

假如有拦截器i1和i2。拦截testAction的execute()方法,示意代码如下:

i1

public String intercept(ActionInvocation invocation) throws Exception {
 	System.out.println("i1 Start!");
 	String result = invocation.invoke();
 	System.out.println("i1 End!");
 	return "i1result";
 
i2

public String intercept(ActionInvocation invocation) throws Exception {
 	System.out.println("i2 Start!");
 	String result = invocation.invoke();
 	System.out.println("i2 End!");
 	return "i2result";
 }
 
testAction

public String execute() throws Exception {
 System.out.println(“execute()”);
 return “success”
 }
 

 ActionProxy调用ActionInvocation的invoke()方法。

 执行//1代码,返回true。

 执行//2代码,返回i1的拦截器映射。

 执行//3代码,调用i1的interceptor()方法,并且把当前ActionInvocation对象传递给interceptor()方法。

 执行i1的interceptor()方法,输出i1 Start。

 i1中调用ActionInvocation的invoke()方法,开始第一次递归调用。

 执行//1代码,返回true。

 执行//2代码,返回i2的拦截器映射对象。

 执行//3代码,调用i2的interceptor()方法,并且把当前ActionInvocation对象传递给interceptor()方法。

 执行i2的interceptor()方法,输出i2 Start。

 i2中调用ActionInvocation的invoke()方法,开始第二次递归调用。

 执行//1代码,返回false。

 执行//4代码,调用目标Action的execute()方法。把返回值赋给resultCode。

 执行//5代码,executed默认为false,所以!executed为true。

 执行//6代码,因为没有结果监听器,所以返回false。

 执行//7代码,执行result。通过resultCode获取物理页面!

 执行//8代码,设置executed为true,表示已经处理结果。

 执行//9代码,返回resultCode到i2的interceptor()。

 i2输出i2 End。

 i2返回i2result,程序流程回到ActionInvocation的invoke()方法的//3位置。

 因为这时executed已经为true,所以invoke()方法直接返回i2result,即i2的返回值。

 流程返回到i1,i1输出i1 End。

 i1返回i1result,程序流程回到ActionInvocation的invoke()方法的//3位置。

 因为这时executed已经为true,所以invoke()方法直接返回i1result,即i1的返回值。

程序流程返回到ActionProxy的execute()方法。

如果i1中没有调用invocation.invoke方法,而是直接返回result,那么i2就不会被执行,而返回结果会变成i1返回的result;如果正常情况下调用了invoke方法,则i1、i2返回的result不会对最终结果造成影响,最终返回的将是action的result。

具体流程图如下:



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值