Struts2 Interceptor Interceptor_struts

Source: Internet
Author: User
Tags aop

Downpour writes that interceptors are the concept of AOP, which is itself a piece of code that can be used to intercept the code of the Interceptor by defining the "weaving point" to execute before and after the "weaving point". As reference in Struts2 above, Struts2 's interceptor, the object of its interception is the action code, which can define the code that executes the interceptor before or after the action code.

Next, we will focus on the internal structure and execution sequence of interceptors in Struts2, and analyze them in combination with source code. Interceptor structure Let's take a look at an action lifecycle diagram we used before:



In the picture, we can find that the interceptor layer of the Struts2, the action wrapped in the innermost. Such a structure, probably has the following characteristics:

1. The entire structure is like a stack, except for the action, the other elements in the stack are interceptor

2. The action is located at the bottom of the stack. Because of the "advanced out" feature of the stack, if we try to take the action out of execution, we must first take out the interceptor at the top of the action. In this way, the entire execution forms a recursive call

3. Each interceptor on the stack needs to complete a special execution function in addition to its own logic. There are 3 options for this executive function:

1) abort the entire execution and return a string directly as ResultCode

2 is responsible for the execution of the next interceptor in the call stack through a recursive call

3 If there is no interceptor in the stack, invoke the action


The design of the STRUTS2 interceptor structure is actually a typical application of the responsibility chain model. The entire execution is first divided into several elements of the same type. Each element has different logical responsibilities and incorporates them into a chain-structured data structure (we can also see the stack structure as a recursive chain structure), and each element is responsible for executing calls to the next element in the chain structure.

This design, from the point of view of code refactoring, is actually a complex system that divide and conquer, so that each part of the logic can be highly reusable and highly scalable. Therefore, interceptor structure is really the essence of the struts2/xwork design of the pen. Definition of interceptor Execution Analysis interceptor

Let's take a look at the definition of Interceptor interface:

Java Code    public interface interceptor extends serializable {          /**       * called to let  an interceptor clean up any resources it has allocated.       */       void destroy ();           /**       * Called after an  interceptor is created, but before any requests are processed  using       * {@link   #intercept ( com.opensymphony.xwork2.ActionInvocation)  intercept} , giving        * the Interceptor a chance to initialize any needed  resources.       */    &NBsp;  void init ();          /**        * allows the interceptor to do some processing on the  request before and/or after the rest of the processing of  the       * request by the {@link  actioninvocation } or to short-circuit the processing and just return a  string return code.       *       * @ return the return code, either returned from {@link  actioninvocation# Invoke ()}, or from the interceptor itself.       *  @throws  exception any system-level error, as defined in {@link   Com.opensymphonY.xwork2.action#execute ()}.       */       string  intercept (actioninvocation invocation)  throws Exception;  }  

There is nothing special about the interface definition of interceptor, except for the Init and Destory methods, The Intercept method is the core method to implement the whole interceptor mechanism. The parameter actioninvocation it relies on is the famous Action Scheduler that we have mentioned in the previous chapters.

Let's take a look at a typical interceptor abstract implementation class:

Java Code    public abstract class aroundinterceptor extends abstractinterceptor  {              /*  (non-javadoc)        *  @see  com.opensymphony.xwork2.interceptor.abstractinterceptor# Intercept (com.opensymphony.xwork2.ActionInvocation)        */         @Override        public string intercept ( actioninvocation invocation)  throws Exception {            String result = null;               before (invocation);           //  Call the next interceptor and execute action           result =  if the interceptor does not exist Invocation.invoke ();   &NBSp;       after (Invocation, result);               return result;       }              public abstract void before ( actioninvocation invocation)  throws Exception;           Public abstract void after (Actioninvocation invocation, string resultcode)   throws exception;     }  

In this implementation class, the prototype of the simplest interceptor has actually been implemented. Maybe everyone is still unfamiliar with the code, it doesn't matter. What I need to point out here is a very important method of Invocation.invoke (). This is the method in Actioninvocation, and Actioninvocation is the action scheduler, so this method has the following 2 layers of meaning:

1. If there are other interceptor in the Interceptor Stack, Invocation.invoke () will invoke the execution of the next interceptor in the stack.

2. If only the action is in the interceptor stack, then Invocation.invoke () invokes action execution.

So, we can see that the invocation.invoke () approach is actually the core of the entire interceptor framework. Based on this implementation mechanism, we can also get the following 2 very important inferences:

1. If in the interceptor we do not use Invocation.invoke () to complete the call of the next element in the stack, but instead return a string directly as the execution result, then the entire execution is aborted.

2. We can divide the code in the interceptor into 2 parts by Invocation.invoke (), and the Code before Invocation.invoke () will be executed sequentially before the action, while in Invocation.invoke () The code that follows will be executed in reverse order after the action.

Thus, we can implement AOP by Invocation.invoke () as the real intercept point of the action code.

Interceptor Intercept Type

From the above analysis, we know that the core part of the entire interceptor is the call location of the Invocation.invoke () function. In fact, we also formally classify the intercept type according to the call location of the code. In Struts2, the interception type of interceptor is divided into the following three categories:

1. Before

Before interception refers to code defined in interceptors that exist before the execution of Invocation.invoke () code. The code is executed sequentially, in the order that the interceptor defines it.

2. After

After interception, refers to code defined in interceptors that exist after the execution of the Invocation.invoke () code. The code, which will be executed in reverse order, is defined by a recruit interceptor.

3. Preresultlistener

Sometimes, before interception and after interception is not enough for us, because we need to do something before the action is done, but before we return to the view layer. STRUTS2 also supports such interception, which is accomplished by registering a Preresultlistener interface in the Interceptor.

Java code public interface Preresultlistener {/** *-callback method would be called after the Action ex       Ecution and before the result execution.  * * @param invocation * @param resultcode/void Beforeresult (actioninvocation invocation, String   ResultCode); }

Here, we see that Struts2 can support so many types of interception, with its own data structure and overall design has a great relationship. As I mentioned in the previous article:

Downpour writes that because the action is an ordinary Java class, rather than a servlet class, completely out of the Web container, we are able to more easily design the control layer at a reasonable level, thus abstracting many common logic, And break the logic out of the action object itself.

As we can see, Struts2 's division of the entire execution, from interceptor to action until result, each layer has a clear responsibility. Not only that, STRUTS2 also set the appropriate insertion point for each level. The expansion of the entire action layer has been upgraded to an unprecedented level.

Interceptor Execution Order

The order of execution of interceptor may be the most concerned part of the whole process. Based on the concepts mentioned above, we have actually been able to get a general idea of the Interceptor's implementation mechanism. Let's take a look at Struts2 's Reference's example of an image of interceptor execution sequence.

If we have a interceptor-stack definition as follows:

XML code <interceptor-stack name= "Xastack" > <interceptor-ref name= "thiswillrunfirstinterceptor"/> <i Nterceptor-ref name= "Thiswillrunnextinterceptor"/> <interceptor-ref name= "Followedbythisinterceptor"/> &L T;interceptor-ref name= "Thiswillrunlastinterceptor"/> </interceptor-stack>

Well, the whole sequence of execution is probably like this:



Here, I have slightly changed the execution order example in Struts2 's reference to make the entire execution order more understandable. As we can see, recursive invocation guarantees that the execution of various types of interception can be organized.

Notice the order in which the code in each interceptor is executed, before the action, the execution order of the interceptor is consistent with that defined in the stack, and after action and result, the Interceptor's execution order is the opposite of the order defined in the stack.
Source analysis Next we will look at the source code, see how Struts2 is to ensure that the interceptor, action and result of the implementation of the order between the three.

As I mentioned before, Actioninvocation is a scheduler in Struts2, so in fact, the scheduling of these codes is done in actioninvocation implementation classes, where I extracted the Invoke () method in Defaultactioninvocation, which will show us everything.

Java code   /**   *  @throws  ConfigurationException If no result  can be found with the returned code   */   public string  invoke ()  throws Exception {       string profilekey  =  "invoke: ";       try {            utiltimerstack.push (profilekey);                           if  ( executed)  {               throw  new illegalstateexception ("action has already executed");            }           //  Call the Interceptor Code execution &NBSP;&N in the interceptor stack in turnBsp         if  (Interceptors.hasnext ())  {                final InterceptorMapping  interceptor =  (interceptormapping)  interceptors.next ();                utiltimerstack.profile ("interceptor: " + Interceptor.getname (),                         new UtilTimerStack.ProfilingBlock<String> ()  {                            public string doprofiling ()  throws  exception {                             //  use Actioninvocation as a parameter to invoke the Intercept method in interceptor                                  resultcode = interceptor.getinterceptor (). Intercept ( Defaultactioninvocation.this);                                return  null;                            }          &NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP});           } else  {               resultcode =  invokeactiononLy ();           }               // this is needed because the result will  be executed, then control will return to the Interceptor,  which will           // return above and  flow through again           if  (! executed)  {               //  Perform preresultlistener               if   (preresultlisteners != null)  {                    for  (iterator iterator =  Preresultlisteners.iterator ();  &nbSp                      iterator.hasnext ();)  {                        PreResultListener listener =  (Preresultlistener)  iterator.next ();                                                     string _profilekey= "preresultlistener: ";                        try {                          &nBsp;     utiltimerstack.push (_profilekey);                                 listener.beforeresult (this, resultcode);                        }                         finally {                                 Utiltimerstack.pop (_profilekey);                        }                    }                }                  //  now execute the result, if we ' re supposed to                // action and Interceptor execution completed, execution result                if  (Proxy.getexecuteresult ( )  {                    executeresult ();                }                   executed = true;           }               return resultcode;       }        finally {           utiltimerstack.pop ( Profilekey);       }  }  

From the source, we can see that the 4 different levels of the Struts2 Action layer that we mentioned earlier are embodied in this approach: interceptors (Interceptor), Action, Preresultlistener, and result. In this method, the orderly invocation and execution of these levels are ensured. From this we can also see that Struts2 in the action level design of many considerations, each level has a high degree of extensibility and insertion point, so that programmers can at any level of liking to add their own implementation mechanism to change action behavior.

Here, the special emphasis is placed on the execution of the interceptor part:

Java Code resultcode = Interceptor.getinterceptor (). Intercept (Defaultactioninvocation.this);

On the surface, it only executes the Intercept method in the interceptor, and if we combine the interceptor, we can see the clue:

Java Code public String intercept (actioninvocation invocation) throws Exception {string result = NULL;           Before (invocation);           Invokes the invocation invoke () method, where a recursive call result = Invocation.invoke () is formed;              After (invocation, result);   return result; }

The Intercept () method is used to recursively call the Actioninvocation invoke () method, and the Actioninvocation loop is nested in intercept () until the statement result = Invocation.invoke () execution ended. In this way, the interceptor will be executed in the reverse order of the first execution, followed by the end.

An ordered list, by recursive invocation, becomes a stack execution process, which makes AOP as a result of an orderly execution of code into a code process that is completely opposite to the sequence of execution in 2 segments. This has become the AOP foundation of the Struts2 action layer.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.