zoukankan      html  css  js  c++  java
  • Structs ActionProxy深度阅读

    ActionProxy是Action的一个代理类,也就是说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法。归根到底,最后调用的是DefaultActionInvocation.invokeAction()方法。
    DefaultActionInvocation()->init()->createAction()。 
    最后通过调用ActionProxy.exute()-->ActionInvocation.invoke()-->Intercepter.intercept()-->ActionInvocation.invokeActionOnly()-->invokeAction()
    这里的步骤是先由ActionProxyFactory创建ActionInvocation和ActionProxy.

    Java代码  收藏代码
    1. public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {  
    2.       
    3.     ActionInvocation inv = new DefaultActionInvocation(extraContext, true);  
    4.     container.inject(inv);  
    5.     return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);  
    6. }  

     下面先看DefaultActionInvocation的init方法

    Java代码  收藏代码
    1. public void init(ActionProxy proxy) {  
    2.     this.proxy = proxy;  
    3.     Map<String, Object> contextMap = createContextMap();  
    4.   
    5.     // Setting this so that other classes, like object factories, can use the ActionProxy and other  
    6.     // contextual information to operate  
    7.     ActionContext actionContext = ActionContext.getContext();  
    8.   
    9.     if (actionContext != null) {  
    10.         actionContext.setActionInvocation(this);  
    11.     }  
    12.     //创建Action,struts2中每一个Request都会创建一个新的Action  
    13.     createAction(contextMap);  
    14.   
    15.     if (pushAction) {  
    16.         stack.push(action);  
    17.         contextMap.put("action", action);  
    18.     }  
    19.   
    20.     invocationContext = new ActionContext(contextMap);  
    21.     invocationContext.setName(proxy.getActionName());  
    22.   
    23.     // get a new List so we don't get problems with the iterator if someone changes the list  
    24.     List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());  
    25.     interceptors = interceptorList.iterator();  
    26. }  
    27.       
    28. protected void createAction(Map<String, Object> contextMap) {  
    29.     // load action  
    30.     String timerKey = "actionCreate: " + proxy.getActionName();  
    31.     try {  
    32.         UtilTimerStack.push(timerKey);  
    33.         //默认为SpringObjectFactory:struts.objectFactory=spring.这里非常巧妙,在struts.properties中可以重写这个属性  
    34.         //在前面BeanSelectionProvider中通过配置文件为ObjectFactory设置实现类  
    35.         //这里以Spring为例,这里会调到SpringObjectFactory的buildBean方法,可以通过ApplicationContext的getBean()方法得到Spring的Bean  
    36.         action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);  
    37.     } catch (InstantiationException e) {  
    38.         throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());  
    39.     } catch (IllegalAccessException e) {  
    40.         throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());  
    41.     } catch (Exception e) {  
    42.        ...  
    43.     } finally {  
    44.         UtilTimerStack.pop(timerKey);  
    45.     }  
    46.   
    47.     if (actionEventListener != null) {  
    48.         action = actionEventListener.prepare(action, stack);  
    49.     }  
    50. }  
    51. //SpringObjectFactory  
    52. public Object buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception {  
    53.     Object o = null;  
    54.     try {  
    55.         //SpringObjectFactory会通过web.xml中的context-param:contextConfigLocation自动注入ClassPathXmlApplicationContext  
    56.         o = appContext.getBean(beanName);  
    57.     } catch (NoSuchBeanDefinitionException e) {  
    58.         Class beanClazz = getClassInstance(beanName);  
    59.         o = buildBean(beanClazz, extraContext);  
    60.     }  
    61.     if (injectInternal) {  
    62.         injectInternalBeans(o);  
    63.     }  
    64.     return o;  
    65. }  

     

    Java代码  收藏代码
    1. //接下来看看DefaultActionInvocation 的invoke方法  
    2. public String invoke() throws Exception {  
    3.     String profileKey = "invoke: ";  
    4.     try {  
    5.         UtilTimerStack.push(profileKey);  
    6.      
    7.         if (executed) {  
    8.             throw new IllegalStateException("Action has already executed");  
    9.         }  
    10.         //递归执行interceptor  
    11.         if (interceptors.hasNext()) {  
    12.             //interceptors是InterceptorMapping实际上是像一个像FilterChain一样的Interceptor链  
    13.             //通过调用Invocation.invoke()实现递归牡循环  
    14.             final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();  
    15.             String interceptorMsg = "interceptor: " + interceptor.getName();  
    16.             UtilTimerStack.push(interceptorMsg);  
    17.             try {    
    18.                  //在每个Interceptor的方法中都会return invocation.invoke()         
    19.                  resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);  
    20.                 }  
    21.             finally {  
    22.                 UtilTimerStack.pop(interceptorMsg);  
    23.             }  
    24.         } else {    
    25.             //当所有interceptor都执行完,最后执行Action,invokeActionOnly会调用invokeAction()方法  
    26.             resultCode = invokeActionOnly();  
    27.         }  
    28.   
    29.         // this is needed because the result will be executed, then control will return to the Interceptor, which will  
    30.         // return above and flow through again    
    31.         //在Result返回之前调用preResultListeners   
    32.         //通过executed控制,只执行一次   
    33.         if (!executed) {  
    34.             if (preResultListeners != null) {   
    35.                 for (Object preResultListener : preResultListeners) {   
    36.                     PreResultListener listener = (PreResultListener) preResultListener;  
    37.                                                                   
    38.                     String _profileKey = "preResultListener: ";   
    39.                     try {                                         
    40.                         UtilTimerStack.push(_profileKey);                               
    41.                         listener.beforeResult(this, resultCode);  
    42.                     }                                             
    43.                     finally {                                     
    44.                         UtilTimerStack.pop(_profileKey);          
    45.                     }                                             
    46.                 }                                                 
    47.             }                                                     
    48.                                                                   
    49.             // now execute the result, if we're supposed to       
    50.             //执行Result                                          
    51.             if (proxy.getExecuteResult()) {                       
    52.                 executeResult();                                  
    53.             }                                                     
    54.                                                                   
    55.             executed = true;                                      
    56.         }                                                         
    57.                                                                   
    58.         return resultCode;                                        
    59.     }                                                             
    60.     finally {                                                     
    61.         UtilTimerStack.pop(profileKey);                           
    62.     }                                                             
    63. }   
    64.   
    65. //invokeAction  
    66. protected String invokeAction(Object action,ActionConfig actionConfig)throws Exception{  
    67.     String methodName = proxy.getMethod();  
    68.   
    69.     String timerKey = "invokeAction: " + proxy.getActionName();  
    70.     try {  
    71.         UtilTimerStack.push(timerKey);  
    72.   
    73.         boolean methodCalled = false;  
    74.         Object methodResult = null;  
    75.         Method method = null;  
    76.         try {  
    77.             //java反射机制得到要执行的方法  
    78.             method = getAction().getClass().getMethod(methodName, new Class[0]);  
    79.         } catch (NoSuchMethodException e) {  
    80.             // hmm -- OK, try doXxx instead  
    81.             //如果没有对应的方法,则使用do+Xxxx来再次获得方法     
    82.             try {  
    83.                 String altMethodName = "do" + methodName.substring(01).toUpperCase() + methodName.substring(1);  
    84.                 method = getAction().getClass().getMethod(altMethodName, new Class[0]);  
    85.             } catch (NoSuchMethodException e1) {  
    86.                 // well, give the unknown handler a shot  
    87.                 if (unknownHandlerManager.hasUnknownHandlers()) {  
    88.                     try {  
    89.                         methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);  
    90.                         methodCalled = true;  
    91.                     } catch (NoSuchMethodException e2) {  
    92.                         // throw the original one  
    93.                         throw e;  
    94.                     }  
    95.                 } else {  
    96.                     throw e;  
    97.                 }  
    98.             }  
    99.         }  
    100.         //执行Method  
    101.         if (!methodCalled) {  
    102.             methodResult = method.invoke(action, new Object[0]);  
    103.         }  
    104.         //从这里可以看出可以Action的方法可以返回String去匹配Result,也可以直接返回Result类  
    105.         if (methodResult instanceof Result) {  
    106.             this.explicitResult = (Result) methodResult;  
    107.   
    108.             // Wire the result automatically  
    109.             container.inject(explicitResult);  
    110.             return null;  
    111.         } else {  
    112.             return (String) methodResult;  
    113.         }  
    114.     } catch (NoSuchMethodException e) {  
    115.         throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");  
    116.     } catch (InvocationTargetException e) {  
    117.         // We try to return the source exception.  
    118.         Throwable t = e.getTargetException();  
    119.   
    120.         if (actionEventListener != null) {  
    121.             String result = actionEventListener.handleException(t, getStack());  
    122.             if (result != null) {  
    123.                 return result;  
    124.             }  
    125.         }  
    126.         if (t instanceof Exception) {  
    127.             throw (Exception) t;  
    128.         } else {  
    129.             throw e;  
    130.         }  
    131.     } finally {  
    132.         UtilTimerStack.pop(timerKey);  
    133.     }  
    134. }  

     action执行完了,还要根据ResultConfig返回到view,也就是在invoke方法中调用executeResult方法。

     

    Java代码  收藏代码
    1. private void executeResult() throws Exception {  
    2.     //根据ResultConfig创建Result   
    3.     result = createResult();  
    4.   
    5.     String timerKey = "executeResult: " + getResultCode();  
    6.     try {  
    7.         UtilTimerStack.push(timerKey);  
    8.         if (result != null) {  
    9.         //开始执行Result,  
    10.         //可以参考Result的实现,如用了比较多的ServletDispatcherResult,ServletActionRedirectResult,ServletRedirectResult   
    11.             result.execute(this);  
    12.         } else if (resultCode != null && !Action.NONE.equals(resultCode)) {  
    13.             throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()  
    14.                     + " and result " + getResultCode(), proxy.getConfig());  
    15.         } else {  
    16.             if (LOG.isDebugEnabled()) {  
    17.                 LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());  
    18.             }  
    19.         }  
    20.     } finally {  
    21.         UtilTimerStack.pop(timerKey);  
    22.     }  
    23. }            
    24.   
    25. public Result createResult() throws Exception {  
    26.     //如果Action中直接返回的Result类型,在invokeAction()保存在explicitResult  
    27.     if (explicitResult != null) {                             
    28.         Result ret = explicitResult;                          
    29.         explicitResult = null;                                
    30.                                                               
    31.         return ret;                                           
    32.     }  
    33.     //返回的是String则从config中得到当前Action的Results列表  
    34.     ActionConfig config = proxy.getConfig();                  
    35.     Map<String, ResultConfig> results = config.getResults();  
    36.                                                               
    37.     ResultConfig resultConfig = null;                         
    38.                                                               
    39.     synchronized (config) {                                   
    40.         try {   
    41.             //通过返回的String来匹配resultConfig    
    42.             resultConfig = results.get(resultCode);           
    43.         } catch (NullPointerException e) {                    
    44.             // swallow                                        
    45.         }                                                     
    46.         if (resultConfig == null) {                           
    47.             // If no result is found for the given resultCode, try to get a wildcard '*' match.  
    48.             //如果找不到对应name的ResultConfig,则使用name为*的Result    
    49.             //说明可以用*通配所有的Result                                
    50.             resultConfig = results.get("*");  
    51.         }                                     
    52.     }                                         
    53.                                               
    54.     if (resultConfig != null) {               
    55.         try {  
    56.             //创建Result   
    57.             return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());  
    58.         } catch (Exception e) {  
    59.             LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);  
    60.             throw new XWorkException(e, resultConfig);  
    61.         }   
    62.     } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {  
    63.         return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);  
    64.     }             
    65.     return null;  
    66. }     
    67.   
    68. public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception {  
    69.     String resultClassName = resultConfig.getClassName();  
    70.     Result result = null;                                  
    71.                                                            
    72.     if (resultClassName != null) {  
    73.         //buildBean中会用反射机制Class.newInstance来创建bean   
    74.         result = (Result) buildBean(resultClassName, extraContext);  
    75.         Map<String, String> params = resultConfig.getParams();       
    76.         if (params != null) {                                        
    77.             for (Map.Entry<String, String> paramEntry : params.entrySet()) {  
    78.                 try {  
    79.                      //reflectionProvider参见OgnlReflectionProvider;  
    80.               //resultConfig.getParams()就是result配置文件里所配置的参数<param></param>   
    81.                      //setProperties方法最终调用的是Ognl类的setValue方法     
    82.               //这句其实就是把param名值设置到根对象result上  
    83.                     reflectionProvider.setProperty(paramEntry.getKey(), paramEntry.getValue(), result, extraContext, true);  
    84.                 } catch (ReflectionException ex) {   
    85.                     if (LOG.isErrorEnabled())        
    86.                         LOG.error("Unable to set parameter [#0] in result of type [#1]", ex,  
    87.                                 paramEntry.getKey(), resultConfig.getClassName());  
    88.                     if (result instanceof ReflectionExceptionHandler) {             
    89.                         ((ReflectionExceptionHandler) result).handle(ex);           
    90.                     }  
    91.                 }      
    92.             }          
    93.         }              
    94.     }                  
    95.                        
    96.     return result;     
    97. }   

     

  • 相关阅读:
    吴裕雄--天生自然C++语言学习笔记:C++ 存储类
    吴裕雄--天生自然C++语言学习笔记:C++ 修饰符类型
    吴裕雄--天生自然C++语言学习笔记:C++ 常量
    吴裕雄--天生自然C++语言学习笔记:C++ 变量作用域
    吴裕雄--天生自然C++语言学习笔记:C++ 变量类型
    吴裕雄--天生自然C++语言学习笔记:C++ 数据类型
    吴裕雄--天生自然C++语言学习笔记:C++ 注释
    吴裕雄--天生自然C++语言学习笔记:C++ 基本语法
    SPOJ375Query on a tree I(树剖+线段树)(询问边)
    HDU5768Lucky7(中国剩余定理+容斥定理)(区间个数统计)
  • 原文地址:https://www.cnblogs.com/lechance/p/4373272.html
Copyright © 2011-2022 走看看