The implementation principle of Spring AOP

Source: Internet
Author: User
Tags throwable

Reflection Implementation AOP Dynamic Proxy Pattern Example description (Implementation principle of Spring AOP)

For example, we are going to develop an application that has a lot of business methods, but we now have to do a full monitoring of the implementation of this method, or part of the monitoring. Maybe we'll just go ahead and add a log to some way, and we'll write an example to see our simplest solution. Let's first write an interface Ihello.java code as follows:

[Java]View Plaincopyprint?
    1. package sinosoft.dj.aop.staticaop;  
    2.   
    3. public  interface ihello {  
    4.     / ** *//** 
    5.       *  Suppose this is a business method  
    6.      *   @param  name 
    7.      */   
    8.     void sayhello (string name) ;   
    9. }  
Package SINOSOFT.DJ.AOP.STATICAOP;  Public interface Ihello {     /** *//**      * Assumes this is a business method      * @param name      *     /void SayHello (String name);

There is a method for entering the name of "Hello" plus the incoming names; let's write a class to implement the Ihello interface.

[Java]View Plaincopyprint?
    1. package sinosoft.dj.aop.staticaop;  
    2.   
    3. public class  hello implements ihello {  
    4.   
    5.     public  void sayhello (string name)  {  
    6.         system.out.println (
    7.     }  
    8.   
    9. }  
Package Sinosoft.dj.aop.staticaop;public class Hello implements Ihello {public    void SayHello (String name) {        System.out.println ("Hello" + Name);}    }

Now we're going to add a logging business to this business method, what do we do without changing the original code? Maybe you'll write a class to implement the Ihello interface and rely on the Hello class. The code is as follows:  1package SINOSOFT.DJ.AOP.STATICAOP;  2  3public class Helloproxy implements Ihello { 4    private ihello hello;  5  6     public helloproxy (Ihello hello) { 7        This.hello = Hello  8   }  9 10    public void SayHello (String name) {11         logger.logging (Level.debuge, "SayHello method start."); 12        Hello.sayhello (name); 13        logger.logging (Level.info, "SayHello method end!"); 15   } 16 17} 18 of them. The Logger class and level enumeration code is as follows: Logger.java  1package SINOSOFT.DJ.AOP.STATICAOP;  2  3import java.util.Date;  4  5public class logger{ 6   /** *//**  7     * Record logs by rank &NBsp;8     * @param level  9     * @param context 10      * * 11    public static void logging (level, String context) {12         if (level.equals (Level.info)) {13            System.out.println (New Date (). toLocaleString () + "" + context); 14       } 15        if (Level.equals ( Level.debuge) {16            System.err.println (new Date) ( ) + "" + context); 17       } 18   } 21level.java

1package SINOSOFT.DJ.AOP.STATICAOP; 2 3public enum level {4    info,debuge; 5} 6 then let's go and write a test class. The code is as follows: test . Java 1package SINOSOFT.DJ.AOP.STATICAOP; 2 3public class Test {4    public static void Main (string[] args) {5      & nbsp Ihello Hello = new Helloproxy (new Hello ()); 6        Hello.sayhello ("Doublej"); 7   } 8} 9 run the above code and we can get the following result:

Tue Mar 20:57:12 CST-SayHello method start. Hello Doublej 2008-3-4 20:57:12 SayHello method end! From the above code we can see that the Hello object is created by Helloproxy this so-called proxy state. This way, if we want to remove the logging function later. So we just change the code that gets the Hello object to the following: 1package SINOSOFT.DJ.AOP.STATICAOP; 2 3public class Test {4    public static void Main (string[] args) {5      & nbsp Ihello Hello = new Hello (); 6        Hello.sayhello ("Doublej"); 7   } 8} 9 The above code, can be said to be the simplest implementation of AOP! But we will find a problem, if we like hello such a lot of classes, then, we are not going to write a lot of helloproxy such a class. Yes, it is. In fact, it is a very troublesome thing. After jdk1.3. The JDK provides us with a api    Java.lang.reflect.InvocationHandler class. This class allows us to do something dynamically when the JVM invokes a method of a class. Let's change the code above to see the effect. Again, we write a Ihello interface and a Hello implementation class. In the interface. We define two methods; The code is as follows:

Ihello.java 1package SINOSOFT.DJ.AOP.PROXYAOP; 2 3public interface Ihello {4/** *//** 5 * Business Process a Method 6 * @param name 7 */8 void SayHello (String n  AME); 9/** *//** 10 * Business Process B method one by one * @param name */void Saygoogbye (String name); 14} 15

Hello.java

 1package SINOSOFT.DJ.AOP.PROXYAOP;  2  3public class Hello implements Ihello { 4  5    public void SayHello (String name) { 6        System.out.println ("Hello" + name);  7   }  8    public void Saygoogbye (String name) { 9   & nbsp;    System.out.println (name+ "goodbye!"); 10   } 11} 12 We're going to write a proxy class just like that. Let this class implement the Java.lang.reflect.InvocationHandler interface, the code is as follows:  1package SINOSOFT.DJ.AOP.PROXYAOP;  2  3import Java.lang.reflect.InvocationHandler;  4import Java.lang.reflect.Method;  5import Java.lang.reflect.Proxy;  6  7public class Dynaproxyhello implements Invocationhandler { 8  9   /** *//** 10& nbsp;    * The object to be processed (that is, the object we want to add business logic to before and after the method, such as Hello in the example) 11     */12     Private Object delegate; 14   /** *//** 15     * The object that is processed by the dynamic generation Method (fixed) 16     * 17     * @ param delegate 18     * @param proxy 19     * @return 20      * * 21    public object bind (object delegate) {22        This.delegate = delegate; 23        return Proxy.newproxyinstance (24                 This.delegate.getClass (). getClassLoader (), This.delegate 25                        . GetClass (). Getinterfaces (), this); 26   } 27   /** *//** 28     * Each method in the object to be processed is sent by this method to the JVM call, i.e., The method of the object to be processed can only be called by this method 29     * This method is dynamic, not manually called 30     */31    public object invoke (object proxy, Method method, object[] args) 32             throws Throwable {33        Object result = null; 34         try {35           // Log 36            logger.logging before the original method is executed (Level.DEBUGE, Method.getname () + "Method end."); 37            38            //JVM This statement to perform the original method (reflection mechanism) 39             result = Method.invoke (this.delegate, args); 40           //record log after executing the original method 41             logger.logging (Level.info, Method.getname () + "method start!"); 42       } catch (Exception e) {43             E.printstacktrace (); 44       } 45       //Return method return value to caller 46         return result; 47   } 48 49} 50 the Logger class and level enumeration that appears in the above class are the same as the implementation of the previous example. The code is not posted here.

Let's write a test class to try it out. The code is as follows: Test.java  1package SINOSOFT.DJ.AOP.PROXYAOP;  2  3public class Test { 4    public static void Main (string[] args) { 5  & nbsp;     Ihello Hello = (ihello) new Dynaproxyhello (). bind (New Hello ());  6        Hello.saygoogbye ("Double J");  7        Hello.sayhello ("Double J");  8         9   } 10} 11 The result of running the output is as follows: Tue Mar 21:24:03 CST 2 008 Saygoogbye Method End. Double J goodbye! 2008-3-4 21:24:03 Saygoogbye Method start! Tue Mar 21:24:03 CST sayHello Method end. Hello Double J 2008-3-4 21:24:03 SayHello Method start! Because of the thread's relationship, the beginning of the second method appears before the end of the first method. This is not our concern! From the above example, we can see that. As long as you are using interface-oriented programming, it is possible for any of your object's methods to be preceded by a logging operation. He (Dynapoxyhello) automatically goes to the agent to execute each method in the Proxied object (Hello), A Java.lang.reflect.InvocationHandler interface will decouple our proxy object from the Proxied object. But we also find that there is another problem that this Dynapoxyhello object can only follow us toAdd logging operations before and after the method. Can we decouple the Dynapoxyhello object from the Log Manipulation object (Logger)? The result is yes. Let's analyze our needs. We want to add the log operation code (or the Code of other operations) before or after the method of the proxy object, so we can abstract an interface that has only two methods and one that executes before the proxy object executes the method , we named start, and the second method is the method that executes after the proxy object executes the method, which we named end. The interface is defined as follows:  1package SINOSOFT.DJ.AOP.PROXYAOP;  2  3import Java.lang.reflect.Method;  4  5public interface IOperation { 6   /** *//**  7     * Method before doing the operation  8     * @param method  9     */10    void Start (method); 11   /** *//** 12     * method After performing the operation 13     * @param method 14      */15    Void End (method); 16} 17 Let's write a class that implements the above interface. We take him as a real operator, as below is a class of log operators: Loggeroperation.java package SINOSOFT.DJ.AOP.PROXYAOP;

Import Java.lang.reflect.Method;

public class Loggeroperation implements IOperation {

public void End (method method) {logger.logging (Level.debuge, Method.getname () + "method end."); }

public void Start (method) {logger.logging (Level.info, Method.getname () + "method start!"); }

}

And then we're going to change the code in the proxy object Dynaproxyhello. As follows:  1package SINOSOFT.DJ.AOP.PROXYAOP;  2  3import Java.lang.reflect.InvocationHandler;  4import Java.lang.reflect.Method;  5import Java.lang.reflect.Proxy;  6  7public class Dynaproxyhello implements Invocationhandler { 8   /** *//**  9& nbsp;    * operator 10     */11    private Object proxy; 12   /** *//** 13     * The object to be processed (that is, the object we want to add business logic to before and after the method, such as Hello in the example) 14      * * 15    private Object delegate; 17   /** *//** 18     * Dynamic Generation method After the object is processed (fixed) 19     * 20& nbsp;    * @param delegate 21     * @param proxy 22     * @return 23     */24    public object Bind (object Delegate,object proxy) {25  & nbsp;     26        this.proxy = proxy; 27        this.delegate = delegate; 28        return Proxy.newproxyinstance (29                 This.delegate.getClass (). getClassLoader (), This.delegate 30                        . GetClass (). Getinterfaces (), this); 31   } 32   /** *//** 33     * Each method in the object to be processed is sent by this method to the JVM call, i.e., The method of the object to be processed can only be called by this method 34     * This method is dynamic, not manually called 35     */36    public object invoke (object proxy, Method method, object[] args) 37             throws Throwable {38        Object result = null; 39         try {40           // Reflection gets the instance of the operator 41            Class clazz = This.proxy.getClass () ; 42           //Reflection gets operator's Start method 43             Method start = Clazz.getdeclaredmethod ("Start", 44                     New Class [] {method.class}); 45           //Reflection execution Start method 46             Start.invoke (This.proxy, new object[] {method}); 47           //Executes the original method to process the object 48             result = Method.invoke (this.delegate, args); 49//            reflection Gets the operator's End method 50             Method end = Clazz.getdeclaredmethod ("End", 51                     New class[] {method.class}); 52//            reflection executes the End method 53             End.invoke (This.proxy, new object[] {method}); 55       } catch (Exception e) {56       & nbsp;    E.printstacktrace (); 57       } 58        return result; 59   } 60 61} 62 then we'll change the code in the Test.java. Test it:

[Java]View Plaincopyprint?
  1. Package SINOSOFT.DJ.AOP.PROXYAOP;
  2. Public class Test {
  3. public static void Main (string[] args) {
  4. Ihello Hello = (ihello)new Dynaproxyhello (). bind (new Hello (),new Loggeroperation ());
  5. Hello.saygoogbye ("Double J");
  6. Hello.sayhello ("Double J");
  7. }
  8. }
Package Sinosoft.dj.aop.proxyaop;public class Test {public    static void Main (string[] args) {        Ihello hello = (Ihel Lo) New Dynaproxyhello (). bind (New Hello (), New Loggeroperation ());        Hello.saygoogbye ("Double J");        Hello.sayhello ("Double J");}            }

The result is still the same.

If you want to add log records before each method, do not add logging to the method. You change the Loggeroperation class to the following: Package SINOSOFT.DJ.AOP.PROXYAOP;    Import Java.lang.reflect.Method; public class Loggeroperation implements ioperation {public void End (method method) {//logger.logging (Lev El.      Debuge, Method.getname () + "method end."); }
public void Start (method) {logger.logging (Level.info, Method.getname () + "method start!"); }
}
Run it. You will find that no log is logged after each method. In this way, we can decouple the agent and the operator!

Let's leave a question for everyone, if we don't want all methods to be logged, how should we go about decoupling? My idea is to add an if () to the public object invoke (object proxy, Method method, object[] args) method in the proxy object, to judge the names of the methods passed in. The condition of the judgment exists in the XML. So we can configure the file to be decoupled. If interested friends can put the operator, the agent is configured through the configuration file, then you can write a simple SPRINGAOP framework.

Some concepts of Spring AOP

http://blog.csdn.net/it_man/article/details/7168570

Facets (Aspect): A focus of modularity, which may be crosscutting across multiple objects. Transaction management is a good example of a crosscutting concern in the Java EE application. In spring AOP, facets can be implemented using generic classes (pattern-based styles) or @aspect annotations (@AspectJ styles) in ordinary classes.

Connection point (Joinpoint): a particular point in the execution of a program, such as when a method is called or when an exception is handled. In spring AOP, a connection point always represents the execution of a method. By declaring a parameter of type Org.aspectj.lang.JoinPoint, you get the connection point information for the body part of the notification (Advice).

Notification (Advice): An action performed on a particular connection point (joinpoint) of a slice. Notifications are available in various types, including notifications such as "Around", "before", and "after". The type of notification is discussed later in this section. Many AOP frameworks, including spring, are notification models with interceptors, and maintain a chain of interceptors centered on the connection point.

Pointcut (Pointcut): an assertion that matches a connection point (Joinpoint). The notification is associated with a pointcut expression and runs on the connection point that satisfies the pointcut (for example, when a method for a particular name is executed). How Pointcut expressions match connection points is the core of AOP: Spring defaults to using the ASPECTJ pointcut syntax.

Introduced (Introduction): (also known as an internal type declaration (Inter-type declaration)). Declare additional methods or fields of a certain type. Spring allows the introduction of new interfaces (and a corresponding implementation) to any Proxied object. For example, you can use an introduction to make the bean implement the IsModified interface to simplify the caching mechanism.

Target object: An object that is notified (advise) by one or more facets (aspect). It is also called the notified (advised) object. Since spring AOP is implemented by the runtime proxy, this object is always a proxy (proxied) object.

AOP Proxy: An object created by the AOP framework to implement a facet contract (aspect contract), including functions such as notification method execution. In spring, an AOP proxy can be either a JDK dynamic agent or a cglib proxy. Note: The latest introduction to Spring 2.0 is the pattern-based (schema-based) style and @aspectj annotation style facet declarations, which are transparent to the users who use these styles.

Weaving (Weaving): Connects a facet (aspect) to another application type or object and creates an object that is notified (advised). These can be done at compile time (for example, with the AspectJ compiler), at class load time, and at run time. Spring, like other pure Java AOP frameworks, completes weaving at run time.

Type of notification:

Pre-notification (before advice): A notification that is executed before a connection point, but this notification does not prevent execution before the connection point (unless it throws an exception).

Notification after return (after returning advice): A notification that is executed after a connection point is completed normally: for example, a method does not throw any exceptions and returns normally.

Notification after an exception is thrown (after throwing advice): the notification that is executed when the method throws an exception exits.

Post notification (after (finally) advice): A notification that is executed when a connection point exits (whether it is a normal return or an unexpected exit).

Surround notification (Around Advice): A notification that encloses a connection point, such as a method call. This is the most powerful type of notification. Surround notifications can accomplish custom behavior before and after a method call. It also chooses whether to continue executing the connection point or to return directly to their own return value or throw an exception to end the execution.

The implementation principle of Spring AOP

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.