Structs ActionProxy deep reading
Actionproxyis a proxy class of the actionaction. It also means that the call of the actionaction is passed through the actionproxyactually. The actual call of the actionproxy.exe cute () method calls the ActionInvocation. invoke () method. In the final analysis, the DefaultActionInvocation. invokeAction () method is called.
DefaultActionInvocation ()-> init ()-> createAction ().
Finally, call ActionProxy. exute () --> ActionInvocation. invoke () --> Intercepter. intercept () --> ActionInvocation. invokeActionOnly () --> invokeAction ()
The steps here are to first create ActionInvocation and ActionProxy by ActionProxyFactory.
Java code
- Public ActionProxy createActionProxy (String namespace, String actionName, String methodName, Map ExtraContext, boolean executeResult, boolean cleanupContext ){
-
- ActionInvocation inv = new DefaultActionInvocation (extraContext, true );
- Container. inject (inv );
- Return createActionProxy (inv, namespace, actionName, methodName, executeResult, cleanupContext );
- }
The following describes the init method of defaactionactioninvocation.
Java code
- Public void init (ActionProxy proxy ){
- This. proxy = proxy;
- Map ContextMap = createContextMap ();
-
- // Setting this so that other classes, like object factories, can use the ActionProxy and other
- // Contextual information to operate
- ActionContext actionContext = ActionContext. getContext ();
-
- If (actionContext! = Null ){
- ActionContext. setActionInvocation (this );
- }
- // Create an Action. Each Request in struts2 creates a new Action.
- CreateAction (contextMap );
-
- If (pushAction ){
- Stack. push (action );
- ContextMap. put ("action", action );
- }
-
- InvocationContext = new ActionContext (contextMap );
- InvocationContext. setName (proxy. getActionName ());
-
- // Get a new List so we don't get problems with the iterator if someone changes the list
- List InterceptorList = new ArrayList (Proxy. getConfig (). getInterceptors ());
- Interceptors = interceptorList. iterator ();
- }
-
- Protected void createAction (Map ContextMap ){
- // Load action
- String timerKey = "actionCreate:" + proxy. getActionName ();
- Try {
- UtilTimerStack. push (timerKey );
- // The default value is SpringObjectFactory: struts. objectFactory = spring. This attribute is very clever. You can override this attribute in struts. properties.
- // In BeanSelectionProvider, set the implementation class for ObjectFactory through the configuration file.
- // Here, Spring is used as an example. Here, the buildBean method of SpringObjectFactory is adjusted. You can use the getBean () method of ApplicationContext to obtain Spring Bean.
- Action = objectFactory. buildAction (proxy. getActionName (), proxy. getNamespace (), proxy. getConfig (), contextMap );
- } Catch (InstantiationException e ){
- Throw new XWorkException ("Unable to intantiate Action! ", E, proxy. getConfig ());
- } Catch (IllegalAccessException e ){
- Throw new XWorkException ("Illegal access to constructor, is it public? ", E, proxy. getConfig ());
- } Catch (Exception e ){
- ...
- } Finally {
- UtilTimerStack. pop (timerKey );
- }
-
- If (actionEventListener! = Null ){
- Action = actionEventListener. prepare (action, stack );
- }
- }
- // SpringObjectFactory
- Public Object buildBean (String beanName, Map ExtraContext, boolean injectInternal) throws Exception {
- Object o = null;
- Try {
- // SpringObjectFactory will automatically inject ClassPathXmlApplicationContext through context-param: contextConfigLocation in web. xml
- O = appContext. getBean (beanName );
- } Catch (NoSuchBeanDefinitionException e ){
- Class beanClazz = getClassInstance (beanName );
- O = buildBean (beanClazz, extraContext );
- }
- If (injectInternal ){
- InjectInternalBeans (o );
- }
- Return o;
- }
Java code
- // Next let's take a look at the invoke method of DefaultActionInvocation.
- Public String invoke () throws Exception {
- String profileKey = "invoke :";
- Try {
- UtilTimerStack. push (profileKey );
-
- If (executed ){
- Throw new IllegalStateException ("Action has already executed ");
- }
- // Recursively execute interceptor
- If (interceptors. hasNext ()){
- // Interceptors are InterceptorMapping, which is actually an Interceptor chain like FilterChain.
- // Call Invocation. invoke () to implement recursive callback Loop
- Final InterceptorMapping interceptor = (InterceptorMapping) interceptors. next ();
- String interceptorMsg = "interceptor:" + interceptor. getName ();
- UtilTimerStack. push (interceptorMsg );
- Try {
- // Return invocation. invoke () in each Interceptor Method ()
- ResultCode = interceptor. getInterceptor (). intercept (defaactionactioninvocation. this );
- }
- Finally {
- UtilTimerStack. pop (interceptorMsg );
- }
- } Else {
- // When all interceptors are completed and finally the Action is executed, invokeActionOnly calls the invokeAction () method
- ResultCode = invokeActionOnly ();
- }
-
- // This is needed because the result will be executed, then control will return to the Interceptor, which will
- // Return abve and flow through again
- // Call preResultListeners before the Result is returned.
- // Execute only once through executed Control
- 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 );
- }
- }
- }
-
- // Now execute the result, if we're re supposed
- // Execute Result
- If (proxy. getExecuteResult ()){
- ExecuteResult ();
- }
-
- Executed = true;
- }
-
- Return resultCode;
- }
- Finally {
- UtilTimerStack. pop (profileKey );
- }
- }
-
- // InvokeAction
- Protected String invokeAction (Object action, ActionConfig actionConfig) throws Exception {
- String methodName = proxy. getMethod ();
-
- String timerKey = "invokeAction:" + proxy. getActionName ();
- Try {
- UtilTimerStack. push (timerKey );
-
- Boolean methodCalled = false;
- Object methodResult = null;
- Method method = null;
- Try {
- // Obtain the method to be executed using the java reflection mechanism
- Method = getAction (). getClass (). getMethod (methodName, new Class [0]);
- } Catch (NoSuchMethodException e ){
- // Hmm -- OK, try doXxx instead
- // If no corresponding method exists, use do + Xxxx to obtain the method again.
- Try {
- String altMethodName = "do" + methodName. substring (0, 1). toUpperCase () + methodName. substring (1 );
- Method = getAction (). getClass (). getMethod (altMethodName, new Class [0]);
- } Catch (NoSuchMethodException e1 ){
- // Well, give the unknown handler a shot
- If (unknownHandlerManager. hasUnknownHandlers ()){
- Try {
- MethodResult = unknownHandlerManager. handleUnknownMethod (action, methodName );
- MethodCalled = true;
- } Catch (NoSuchMethodException e2 ){
- // Throw the original one
- Throw e;
- }
- } Else {
- Throw e;
- }
- }
- }
- // Execute Method
- If (! MethodCalled ){
- MethodResult = method. invoke (action, new Object [0]);
- }
- // From this we can see that the Action method can return a String to match the Result, or directly return the Result class.
- If (methodResult instanceof Result ){
- This. explicitResult = (Result) methodResult;
-
- // Wire the result automatically
- Container. inject (explicitResult );
- Return null;
- } Else {
- Return (String) methodResult;
- }
- } Catch (NoSuchMethodException e ){
- Throw new IllegalArgumentException ("The" + methodName + "() is not defined in action" + getAction (). getClass () + "");
- } Catch (InvocationTargetException e ){
- // We try to return the source exception.
- Throwable t = e. getTargetException ();
-
- If (actionEventListener! = Null ){
- String result = actionEventListener. handleException (t, getStack ());
- If (result! = Null ){
- Return result;
- }
- }
- If (t instanceof Exception ){
- Throw (Exception) t;
- } Else {
- Throw e;
- }
- } Finally {
- UtilTimerStack. pop (timerKey );
- }
- }
After the action is executed, view is returned Based on ResultConfig, that is, the executeResult method is called in the invoke method.
Java code
- Private void executeResult () throws Exception {
- // Create Result Based on ResultConfig
- Result = createResult ();
-
- String timerKey = "executeResult:" + getResultCode ();
- Try {
- UtilTimerStack. push (timerKey );
- If (result! = Null ){
- // Start executing Result,
- // You can refer to the implementation of Result, for example, using more ServletDispatcherResult, ServletActionRedirectResult, ServletRedirectResult
- Result.exe cute (this );
- } Else if (resultCode! = Null &&! Action. NONE. equals (resultCode )){
- Throw new ConfigurationException ("No result defined for action" + getAction (). getClass (). getName ()
- + "And result" + getResultCode (), proxy. getConfig ());
- } Else {
- If (LOG. isDebugEnabled ()){
- LOG. debug ("No result returned for action" + getAction (). getClass (). getName () + "at" + proxy. getConfig (). getLocation ());
- }
- }
- } Finally {
- UtilTimerStack. pop (timerKey );
- }
- }
-
- Public Result createResult () throws Exception {
- // If the Result type returned directly in the Action, the invokeAction () is saved in the explicitResult
- If (explicitResult! = Null ){
- Result ret = explicitResult;
- ExplicitResult = null;
-
- Return ret;
- }
- // If the String is returned, the current Action's Results list is obtained from config.
- ActionConfig config = proxy. getConfig ();
- Map Results = config. getResults ();
-
- ResultConfig resultConfig = null;
-
- Synchronized (config ){
- Try {
- // Match resultConfig with the returned String
- ResultConfig = results. get (resultCode );
- } Catch (NullPointerException e ){
- // Swallow
- }
- If (resultConfig = null ){
- // If no result is found for the given resultCode, try to get a wildcard '*' match.
- // If ResultConfig of the corresponding name cannot be found, use the Result with name *
- // You can use * to assign all results.
- ResultConfig = results. get ("*");
- }
- }
-
- If (resultConfig! = Null ){
- Try {
- // Create Result
- Return objectFactory. buildResult (resultConfig, invocationContext. getContextMap ());
- } Catch (Exception e ){
- LOG. error ("There was an exception while instantiating the result of type" + resultConfig. getClassName (), e );
- Throw new XWorkException (e, resultConfig );
- }
- } Else if (resultCode! = Null &&! Action. NONE. equals (resultCode) & unknownHandlerManager. hasUnknownHandlers ()){
- Return unknownHandlerManager. handleUnknownResult (invocationContext, proxy. getActionName (), proxy. getConfig (), resultCode );
- }
- Return null;
- }
-
- Public Result buildResult (ResultConfig resultConfig, Map ExtraContext) throws Exception {
- String resultClassName = resultConfig. getClassName ();
- Result result = null;
-
- If (resultClassName! = Null ){
- // BuildBean will use the reflection mechanism Class. newInstance to create bean
- Result = (Result) buildBean (resultClassName, extraContext );
- Map Params = resultConfig. getParams ();
- If (params! = Null ){
- For (Map. Entry ParamEntry: params. entrySet ()){
- Try {
- // For reflectionProvider, see OgnlReflectionProvider;
- // ResultConfig. getParams () is the parameter configured in the result configuration file.
- // The setProperties method calls the setValue method of the Ognl class.
- // Set the param name value to the result of the root object.
- ReflectionProvider. setProperty (paramEntry. getKey (), paramEntry. getValue (), result, extraContext, true );
- } Catch (ReflectionException ex ){
- If (LOG. isErrorEnabled ())
- LOG. error ("Unable to set parameter [#0] in result of type [#1]", ex,
- ParamEntry. getKey (), resultConfig. getClassName ());
- If (result instanceof ReflectionExceptionHandler ){
- (ReflectionExceptionHandler) result). handle (ex );
- }
- }
- }
- }
- }
-
- Return result;
- }