Interceptor Implementation Principle

Source: Internet
Author: User

Interceptors (Interceptor) are one of the most powerful features of Struts2, and can be said to be the core of struts2, which allows you to do some processing before or after action and result are executed. At the same time, interceptors allow you to modularize generic Code and act as a reusable class. Many of the features in Struts2 are done by interceptors. Interception is an implementation strategy of AOP. The Chinese document in WebWork is interpreted as: Interceptors are objects that dynamically intercept action calls. It provides a mechanism to enable developers to define code that executes before and after an action executes, or to prevent it from executing before an action executes. It also provides a way to extract the reusable parts of an action. When it comes to interceptors, there's one more word you should know-the interceptor chain (Interceptor Chain, called the Interceptor stack interceptor stack in struts 2). The Interceptor chain is a chain that binds the interceptor in a certain order. When accessing an intercepted method or field, interceptors in the interceptor chain are called in the order in which they were previously defined.

A The implementation principle of interceptors:

Most of the time, the Interceptor method is invoked in the form of proxies. The block implementation of Struts 2 is relatively straightforward. When the request arrives at the servletdispatcher of Struts 2, struts 2 looks for the configuration file, instantiates the relative interceptor object based on its configuration, and then strings it into a list, the last one to invoke the interceptor in the list. In fact, the reason we are able to use interceptors so flexibly is due to the use of dynamic agents . A dynamic agent is a proxy object that makes different processing based on the customer's needs. For the customer, just know a proxy object on the line. In that Struts2, How is the interceptor invoked through a dynamic proxy ? When the action request arrives, an action proxy object is generated by the agent of the system, which invokes the action's execute () or the specified method, and finds the interceptor corresponding to the action in Struts.xml. If there is a corresponding interceptor, these interceptors are called before the action's method executes, and if there is no corresponding interceptor, the action method is executed. The system's call to the Interceptor is implemented by Actioninvocation. The code is as follows:

[Java]View Plaincopyprint?
    1. if (Interceptors.hasnext ()) {
    2. Interceptor Interceptor= (Interceptor) Interceptors.next ();
    3. ResultCode = Interceptor.intercept (this);
    4. } Else {
    5. if (Proxy.getconfig (). Getmethodname () = = null) {
    6. ResultCode = Getaction (). Execute ();
    7. } Else {
    8. ResultCode = Invokeaction (Getaction (), Proxy.getconfig ());
    9. }
    10. }


You can see that the action is not directly associated with the interceptor, but rather that the agent works with the interceptor in the organization action. Such as:

Two Interceptor Execution Analysis

As we all know, there is nothing special about the interface definition of interceptor, except the Init and Destory methods, The Intercept method is the core method to implement the whole interceptor mechanism. And it relies on the parameter actioninvocation is the famous action dispatcher. Let's take a look at a typical interceptor abstract implementation class:

[Java]View Plaincopyprint?
  1. Public abstract class Aroundinterceptor extends Abstractinterceptor {
  2. /* (Non-javadoc)
  3. * @see Com.opensymphony.xwork2.interceptor.abstractinterceptor#intercept ( Com.opensymphony.xwork2.ActionInvocation)
  4. */
  5. @Override
  6. Public String intercept (actioninvocation invocation) throws Exception {
  7. String result = null;
  8. Before (invocation);
  9. //Call the next interceptor, if the interceptor does not exist, execute the action
  10. result = Invocation.invoke ();
  11. After (invocation, result);
  12. return result;
  13. }
  14. Public abstract Void before (Actioninvocation invocation) throws Exception;
  15. Public abstract void after (actioninvocation invocation, String ResultCode) throws Exception;
  16. }


In this implementation class, you have actually implemented the simplest interceptor prototype. What needs to be pointed out here is a very important method of Invocation.invoke (). This is the method in Actioninvocation, and Actioninvocation is the action dispatcher, so this method has the following 2-layer meanings:

1. If there are other interceptor in the interceptor stack, then Invocation.invoke () will call the execution of the next interceptor in the stack.
2. If there is only action in the interceptor stack, then Invocation.invoke () will invoke action execution.


So, we can see that the Invocation.invoke () method is actually the core of the entire interceptor framework implementation. 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 of the stack, but instead directly return a string as the result of execution, then the entire execution will be aborted.
2. We can divide the code in the interceptor into 2 parts with Invocation.invoke (), and the Code before Invocation.invoke () will be executed sequentially before the action, and in Invocation.invoke () The subsequent code 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.


Three. Source code parsing


Let's look at the source code to see how STRUTS2 guarantees the order of execution between the Interceptor, action, and result. As I mentioned before, Actioninvocation is the scheduler in the Struts2, so in fact, the execution of these code is done in the Actioninvocation implementation class, here, I extracted the Invoke () method in Defaultactioninvocation, which will show us everything.


  1. /**
  2. * @throws configurationexception If No result can be found with the returned code
  3. */
  4. Public String Invoke () throws Exception {
  5. String Profilekey = "Invoke:";
  6. try {
  7. Utiltimerstack.push (Profilekey);
  8. if (executed) {
  9. throw New IllegalStateException ("Action has already executed");
  10. }
  11. ///Call the Interceptor Code execution in the interceptor stack in turn
  12. if (Interceptors.hasnext ()) {
  13. Final Interceptormapping Interceptor = (interceptormapping) interceptors.next ();
  14. Utiltimerstack.profile ("Interceptor:" +interceptor.getname (),
  15. New Utiltimerstack.profilingblock<string> () {
  16. Public String doprofiling () throws Exception {
  17. //Actioninvocation as a parameter, call the Intercept method in interceptor to execute
  18. ResultCode = Interceptor.getinterceptor (). Intercept (defaultactioninvocation.   this);
  19. return null;
  20. }
  21. });
  22. } Else {
  23. ResultCode = Invokeactiononly ();
  24. }
  25. //This is needed because the result would be executed and then control would return to the interceptor, which would
  26. //return above and flow through again
  27. if (!executed) {
  28. //Execute Preresultlistener
  29. if (preresultlisteners! = null) {
  30. For (Iterator Iterator = Preresultlisteners.iterator ();
  31. Iterator.hasnext ();) {
  32. Preresultlistener listener = (Preresultlistener) iterator.next ();
  33. String _profilekey="Preresultlistener:";
  34. try {
  35. Utiltimerstack.push (_profilekey);
  36. Listener.beforeresult (this, ResultCode);
  37. }
  38. finally {
  39. Utiltimerstack.pop (_profilekey);
  40. }
  41. }
  42. }
  43. //Now execute the result, if we ' re supposed to
  44. //action and interceptor executed, execution result
  45. if (Proxy.getexecuteresult ()) {
  46. Executeresult ();
  47. }
  48. executed = true;
  49. }
  50. return resultcode;
  51. }
  52. finally {
  53. Utiltimerstack.pop (Profilekey);
  54. }
  55. }



From the source code, we can see the Action layer of the 4 different levels, in this method is reflected, they are: Interceptor (Interceptor), Action, Preresultlistener and result. In this method, the sequential invocation and execution of these levels are ensured. As a result, we can see that Struts2 's many considerations in the action hierarchy design, each level has a high degree of extensibility and insertion point, allowing programmers to add their own implementation mechanism at any preferred level to change action behavior.
Here, a special emphasis is placed on the execution invocation of the interceptor part:

[Java]View Plaincopyprint?
    1. ResultCode = Interceptor.getinterceptor (). Intercept (defaultactioninvocation.     this);




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

[Java]View Plaincopyprint?
  1. Public String intercept (actioninvocation invocation) throws Exception {
  2. String result = null;
  3. Before (invocation);
  4. //Call the Invoke () method of invocation, where a recursive call is formed
  5. result = Invocation.invoke ();
  6. After (invocation, result);
  7. return result;
  8. }


Originally in The Intercept () method and the Actioninvocation invoke () method recursive call, actioninvocation loop nested in intercept (), until the statement result = Invocation.invoke () execution ends. In this way, the interceptor is executed in the reverse order in which it was first executed. an ordered linked list, which is transformed into a stack execution by recursive invocation, turns an orderly execution of code into a 2-stage code process that executes exactly the opposite sequence, thus subtly implementing AOP. This also becomes the AOP foundation of the action layer of the Struts2.

Interceptor Implementation Principle

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.