struts2的ActionInvocation分析(action调度者)

        一个ActionInvocation实例代表一个action的执行状态,持有拦截器和将要执行的action的实例。

defaultActionInvocation是其默认实现。下面是定义在该类中的部分成员变量

public class DefaultActionInvocation implements ActionInvocation {
    protected Object action;
    protected ActionProxy proxy;
    protected List<PreResultListener> preResultListeners;
    protected ActionContext invocationContext;
    protected Iterator<InterceptorMapping> interceptors;
    protected String resultCode;
}

        成员变量的含义:

        action:用于接收一次请求中含有本次请求的处理逻辑的类。就是对应的struts.xml配置文件中

                      的action对应的class类的对象。比如struts.xml中有

                     <action name="login" class="com.xxx.LoginAction"></action>这个 配置片段。如果请求

                     的action的name为login,那么defaultActionInvocation中的action成员变量将持有 一个

                     com.xxx.LoginAction的实例。

        proxy:action的执行环境,持有action执行所需的所有信息。

        preResultListeners:一个监听器集合。这些监听器会在action执行完毕且Result执行之前调用。

        invocationContext:action执行的环境,包含action执行需要的session,parameters,locale等 信息

        interceptors:ActionInvocation的重要的部分。包含了action执行过程中的所有拦截器,用于对action

                                进行预处理和后处理。拦截器的调用方式采用责任链模式,和Servlet中的过滤器的

                                执行过程相似

        resultCode:action调用execute等方法处理完相应的逻辑后的返回值。比如success,login等。


        下面分析defaultActionInvocation中的重要方法:invokeActionOnly,invokeAction和invoke方法

        首先是invokeActionOnly方法,如下

public String invokeActionOnly() throws Exception {
    return invokeAction(getAction(), proxy.getConfig());
}

        该方法先通过getAction方法获取实际请求的action实例,并通过proxy获取构建ActionProxy对象的

ActionConfig实例。ActionConfig包含了一个action在struts.xml文件中的相关的配置信息。


        接着是invokeAction方法,该方法只保留了源码中的一些关键部分,并不是完整的

protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {

	//通过getMethod获取在action配置文件中配置的要执行的方法
        String methodName = proxy.getMethod();

        try {
            boolean methodCalled = false;
            Object methodResult = null;
            Method method = null;
	    try {
	      //getAction方法获取实际的action对象,然后获得它的
	      //Class对象,在通过getMethod方法,以反射的方式获得
	      //将要执行的方法
	       method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);

		} catch (NoSuchMethodException e) {
		try {
	            String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
		    method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY);
		} catch (NoSuchMethodException e1) {
		...
		}
	      }
            
           }
	    //如果该方法还未执行过,那么通过反射调用该方法
            if (!methodCalled) {
                methodResult = method.invoke(action, new Object[0]);
            }

        }
		...
    }


         最后是最重要的invoke方法,保留了完整的代码,并加入了自己的理解注释(责任链模式)。如下

public String invoke() throws Exception {
	    String profileKey = "invoke: ";
        try {
            UtilTimerStack.push(profileKey);

            if (executed) {
                throw new IllegalStateException("Action has already executed");
            }

	    //当前还有拦截器,则取出拦截器执行intercept方法
            if (interceptors.hasNext()) {
		//取出当前要执行的拦截器
                final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);
                try {
		    //执行拦截方法intercept,回去返回结果。传入DefaultActionInvocation.this
		    //参数是因为拦截器本身会调用ActionInvocation的invoke方法,因为实际类型是
		    //defaultActionInvocation,根据多态性,执行流程又会回到
		    //defaultActionInvocation的invoke方法,因为是同一个defaultActionInvocation
		    //那么就会取之前拦截器的下一个拦截器继续执行intercept方法
                    resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                
		} finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {//当前没有拦截器,那么调用请求的action中的处理方法
                resultCode = invokeActionOnly();
            }

            //PreResultListener会在action执行完后,Result执行之前执行,且只
	    //执行一次。使用了一个boolean类型的标志,若没有执行,则执行这些
	    //监听器。因为是在同一个ActionInvocation的实例中,所以当executed
	    //成员变量变为true后,之后的if判断通不过,就不在执行了
            if (!executed) {
                if (preResultListeners != null) {
                    for (Object preResultListener : preResultListeners) {
                        PreResultListener listener = (PreResultListener) preResultListener;
                        String _profileKey = "preResultListener: ";
                        try {
                            UtilTimerStack.push(_profileKey);
                            listener.beforeResult(this, resultCode);
                        }
                        finally {
                            UtilTimerStack.pop(_profileKey);
                        }
                    }
                }

		//可以看到PreResultListener的执行是在action执行后,Result执行前
                if (proxy.getExecuteResult()) {
                    executeResult();
                }
                executed = true; //设置为true,保证PreResultListener不再执行
            }

            return resultCode; //返回action执行完毕后的返回值
        }
        finally {
            UtilTimerStack.pop(profileKey);
        }
    }    

        Action的调用者使用以上三个方法来完成请求的拦截和相应的action方法的执行。成员变量中最重要的

就是表示实际Action类的action和拦截器的集合interceptors。interceptors持有所有对action请求进行拦截的

拦截器引用,而action成员变量持有对请求进行实际处理的类的对象。

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值