The misunderstood interceptor in struts2

Source: Internet
Author: User

 

The interceptor in struts2 is widely talked about and varied. Here are several common online sayings:

1. The principle of interceptor is dynamic proxy. (Nima)

2. The principle of interceptor is the responsibility chain model. (If there is no interceptor chain, it means it adopts the responsibility chain mode)

3. interceptor is AOP. (Nima, do you know AOP ?)

4. interceptor adopts the AOP idea. (This is correct)

5. interceptor adopts the AOP idea, so it is implemented based on dynamic proxy. (I just want to say that dynamic proxy can implement AOP, but AOP is not a dynamic proxy. Even if you know that AOP is implemented using dynamic proxy in spring, don't be partial)

 

I am right. I will not discuss it for the moment. Can I check the struts2 source code?

 

Struts2 interceptor source code analysis

 

Interceptor Interface Description:

/* An interceptor is a stateless class that follows the interceptor pattern, as * found in {@link  javax.servlet.Filter} and in AOP languages. * Interceptors are objects that dynamically intercept Action invocations. * They provide the developer with the opportunity to define code that can be executed * before and/or after the execution of an action. They also have the ability * to prevent an action from executing. Interceptors provide developers a way to * encapulate common functionality in a re-usable form that can be applied to one or more Actions. * / 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.     */    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.     *     * @param invocation the action invocation     * @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; }
View code

 

You can learn from the description of interceptor interface:

1. interceptor is a stateless class that adopts the interceptor mode. There are also javax. servlet. Filter and definitions in AOP. (This is the principle of interceptor)

2. interceptor is an object that dynamically intercepts action calls. interceptor can be used to add functions before or after an action call. It can also prevent action execution. With the interceptor, you can define some common functions and then use them for multiple actions. (This is an interceptor function)

Next let's take a look at the code structure:

 

Find a simple interceptor implementation class logginginterceptor:

Public class logginginterceptor extends actinterceptor {Private Static final logger log = loggerfactory. getlogger (logginginterceptor. class); Private Static final string finish_message = "Finishing execution stack for action"; Private Static final string start_message = "Starting execution stack for action"; @ override Public String intercept (actioninvocation Invocation) throws exception {// Add logmessage (invocation, start_message) before action/interceptor calls; // The next interceptor executes or executes action string result = invocation. invoke (); // Add the function logmessage (invocation, finish_message); return result;} private void logmessage (actioninvocation invocation, string basemessage) {If (log. isinfoenabled () {stringbuilder message = new stringbuilder (basemessage); string namespace = invocation. Getproxy (). getnamespace (); If (namespace! = NULL) & (namespace. trim (). length ()> 0) {message. append (namespace ). append ("/");} message. append (invocation. getproxy (). getactionname (); log.info (message. tostring ());}}}
View code

Let's take a look at the default Implementation of actioninvocation in struts2:

// Only part of the code is copied, because this class is relatively large public class defaultactioninvocation implements actioninvocation {protected actioncontext invocationcontext; protected iterator <interceptormapping> interceptors; protected valuestack stack; protected result; protected result explicitresult; protected string resultcode; protected Boolean executed = false; // invoke method Public String invoke () throws exception {string profi Lekey = "INVOKE:"; try {utiltimerstack. push (profilekey); If (executed) {Throw new illegalstateexception ("action has already executed");} If (interceptors. hasnext () {final interceptormapping interceptor = (interceptormapping) interceptors. next (); string interceptormsg = "Interceptor:" + interceptor. getname (); utiltimerstack. push (interceptormsg); try {resultcode = interceptor. getinterceptor (). Intercept (defaactionactioninvocation. this);} finally {utiltimerstack. pop (interceptormsg) ;}} 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) {If (preresultlisteners! = NULL) {for (Object preresultlistener: preresultlisteners) {preresultlistener listener = (preresultlistener) preresultlistener; string _ profilekey = "Maid:"; try {utiltimerstack. push (_ profilekey); listener. beforeresult (this, resultcode);} finally {utiltimerstack. pop (_ profilekey) ;}}// now execute the result, if we're supposed to If (proxy. getexecuteresult () {executeresult ();} executed = true;} return resultcode;} finally {utiltimerstack. pop (profilekey );}}
View code

It can be seen from this class that the function does meet the purpose of appending a function before/after an action call. When the next interceptor is called, The actioninvocation. Invoke () method is used. Next let's take a look at the design of defaultactioninvocation:

Simplify the above defaultactioninvocation class:

Public defaultactioninvocation implements actioninvocation {

Protected iterator <interceptormapping> interceptors;

Public String invoke (){

If (interceptors. hasnext ()){

Interceptormapping mapping = (interceptormapping) interceptors. Next ();

Interceptor indium = mapping. getinterceptor ();

String resultcode = indium. Interceptor (this );

}

}

}

 

Now we want to use a UML class diagram to express the specific implementation of interceptor:

 

 

 

Compared with the class chart made during filter in the last mode:

 

Comparison of interceptor in Filter Design:

1. the interceptor interface is the same as the filter interface.

2. The actioninvocation interface is the same as the filterchain interface.

3. filtercontext is actually a list <filter>. defaultfilterchain contains a filtercontext, which is actually a list <filter> included in defaultfilterchain;

Defaultactioninvocation also includes a set: iterator <interceptormapping>. In this case, the design is the same.

 

4. Check the execution process:

Filter execution:

Public void dofilter (request, reponse, filterchain ){

Filterchain. dofilter ();

}

Interceptor:

Public String intercept (actioninvacation invoker ){

Invoker. Invoke ();

}

 

5. Let's see how to call it:

In the implementation class of filterchain:

Dofilter (request, response ){

Filter filter = context. getfilters. Get (I );

Filter. dofilter (request, response, this );

}

 

In the implementation class of actioninvocation:

Invoke (){

Iterator. Next (). getinterceptor. Invoke (this );

}

 

To this point, do I still think it is a dynamic proxy? Do you still think it is the responsibility chain model? Since the code has been mentioned to this point, you don't have to simulate Interceptor. It's just a replica of the filter.

 

Since it is not a dynamic proxy, it is not a responsibility chain model. Is it AOP? It is said officially.

Check whether:

AOP

Advice, pointcut, join point, target, aspect;

AOP process:

During the compiler or runtime, on the target, locate the joinpoint that matches the pointcut, and attach it to advice before (or/and.

 

Arrange interceptor according to the AOP process:

At runtime, in the action class, find the xxexecute (or execute) method that matches the ** execute method to add auxiliary functions.

That is to say, in the intercept method of interceptor, advice is added before and after calling actioninvocation. Invoke.

 

So interceptor and filter all adopt the AOP programming idea. In addition, interceptor is used to provide advice (additional functions ).

 

Let's talk about how to define interceptor in the AOP Alliance:

package org.aopalliance.aop;/** * Tag interface for Advice. Implementations can be any type * of advice, such as Interceptors. * @author Rod Johnson * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $ */public interface Advice { }   package org.aopalliance.intercept; /** * This interface represents an invocation in the program. * * <p>An invocation is a joinpoint and can be intercepted by an * interceptor. * * @author Rod Johnson */ public interface Invocation extends Joinpoint {     /**    * Get the arguments as an array object.    * It is possible to change element values within this    * array to change the arguments.    *    * @return the argument of the invocation */   Object[] getArguments(); }

Now, the truth is clear.

 

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.