• 【转】struts2的ActionInvocation分析(action调度者)


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

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

    1 public class DefaultActionInvocation implements ActionInvocation {
    2     protected Object action;
    3     protected ActionProxy proxy;
    4     protected List<PreResultListener> preResultListeners;
    5     protected ActionContext invocationContext;
    6     protected Iterator<InterceptorMapping> interceptors;
    7     protected String resultCode;
    8 }

            成员变量的含义:

            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方法,该方法只保留了源码中的一些关键部分,并不是完整的

     1 protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
     2  
     3        //通过getMethod获取在action配置文件中配置的要执行的方法
     4         String methodName = proxy.getMethod();
     5  
     6         try {
     7             boolean methodCalled = false;
     8             Object methodResult = null;
     9             Method method = null;
    10           try {
    11              //getAction方法获取实际的action对象,然后获得它的
    12              //Class对象,在通过getMethod方法,以反射的方式获得
    13              //将要执行的方法
    14              method = getAction().getClass().getMethod(methodName, EMPTY_CLASS_ARRAY);
    15  
    16           } catch (NoSuchMethodException e) {
    17             try {
    18                   String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
    19                  method = getAction().getClass().getMethod(altMethodName, EMPTY_CLASS_ARRAY);
    20             } catch (NoSuchMethodException e1) {
    21               ...
    22             }
    23            }            
    25        }
    26        //如果该方法还未执行过,那么通过反射调用该方法
    27        if (!methodCalled) {
    28            methodResult = method.invoke(action, new Object[0]);
    29        }
    30     ...
    31 }

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

     1 public String invoke() throws Exception {
     2         String profileKey = "invoke: ";
     3         try {
     4             UtilTimerStack.push(profileKey);
     5  
     6             if (executed) {
     7                 throw new IllegalStateException("Action has already executed");
     8             }
     9  
    10            //当前还有拦截器,则取出拦截器执行intercept方法
    11             if (interceptors.hasNext()) {
    12             //取出当前要执行的拦截器
    13                 final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
    14                 String interceptorMsg = "interceptor: " + interceptor.getName();
    15                 UtilTimerStack.push(interceptorMsg);
    16                 try {
    17                 //执行拦截方法intercept,回去返回结果。传入DefaultActionInvocation.this
    18                 //参数是因为拦截器本身会调用ActionInvocation的invoke方法,因为实际类型是
    19                 //defaultActionInvocation,根据多态性,执行流程又会回到
    20                 //defaultActionInvocation的invoke方法,因为是同一个defaultActionInvocation
    21                 //那么就会取之前拦截器的下一个拦截器继续执行intercept方法
    22                     resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
    23                 
    24              } finally {
    25                     UtilTimerStack.pop(interceptorMsg);
    26                 }
    27             } else { //当前没有拦截器,那么调用请求的action中的处理方法
    28                 resultCode = invokeActionOnly();
    29             }
    30  
    31              //PreResultListener会在action执行完后,Result执行之前执行,且只
    32            //执行一次。使用了一个boolean类型的标志,若没有执行,则执行这些
    33            //监听器。因为是在同一个ActionInvocation的实例中,所以当executed
    34            //成员变量变为true后,之后的if判断通不过,就不在执行了
    35             if (!executed) {
    36                 if (preResultListeners != null) {
    37                     for (Object preResultListener : preResultListeners) {
    38                         PreResultListener listener = (PreResultListener) preResultListener;
    39                         String _profileKey = "preResultListener: ";
    40                         try {
    41                             UtilTimerStack.push(_profileKey);
    42                             listener.beforeResult(this, resultCode);
    43                         }
    44                         finally {
    45                             UtilTimerStack.pop(_profileKey);
    46                         }
    47                     }
    48                 }
    49  
    50              //可以看到PreResultListener的执行是在action执行后,Result执行前
    51                 if (proxy.getExecuteResult()) {
    52                     executeResult();
    53                 }
    54                 executed = true; //设置为true,保证PreResultListener不再执行
    55             }
    56  
    57             return resultCode; //返回action执行完毕后的返回值
    58         }
    59         finally {
    60             UtilTimerStack.pop(profileKey);
    61         }
    62     }    

            Action的调用者使用以上三个方法来完成请求的拦截和相应的action方法的执行。成员变量中最重要的就是表示实际Action类的action和拦截器的集合interceptors。interceptors持有所有对action请求进行拦截的拦截器引用,而action成员变量持有对请求进行实际处理的类的对象。

    转载:https://blog.csdn.net/ikaraide/article/details/17719823

  • 相关阅读:
    HttpClient使用
    十九、springboot使用@ControllerAdvice(二)之深入理解
    如何同步删除svn管理的package包目录
    在使用FastJson开发遇到的的坑
    解决tomcat端口被占用:Port 8005 required by Tomcat v7.0 Server at localhost is already in use
    SpringBoot使用Mybatis-Generator
    SpringCloud Gateway入门
    使用Nginx部署静态网站
    SpringBoot使用Jsp
    SpringBoot应用War包形式部署到外部Tomcat
  • 原文地址:https://www.cnblogs.com/day1day1up/p/11179997.html
Copyright © 2020-2023  润新知