Reflection implements AOP Dynamic Proxy mode (Spring AOP implementation principle)

Source: Internet
Author: User

In fact, the meaning of AOP is to face-slicing programming.

OO focuses on our approach to problem solving (encapsulated into method), while AOP focuses on the common denominator of many problem-solving approaches, and is a complement to oo thinking!

Let's take an example that people often cite:

For example, we are going to develop an application that has a lot of business methods in it, but we are now going to do a full monitoring of the implementation of this method, or some monitoring. Maybe we'll just go ahead and add a log record.

Let's write an example to see our simplest solution

Let's first write an interface Ihello.java code as follows:


package sinosoft.dj.aop.staticaop;  public interface ihello {      /** *//**      *  Suppose this is a business method      *   @param  name      */     void sayhello ( String name,  } There is a method for entering "Hello"   The name of the incoming; let's write a class to implement the Ihello interface 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: package sinosoft.dj.aop.staticaop;   public class HelloProxy implements IHello {      private ihello hello;      public helloproxy (Ihello hello)  {          this.hello = hello;     }    public void  SayHello (String name)  {      logger.logging (level.debuge,  " Sayhello method start. ");        hello.sayhello (name);        Logger.logging (level.info,  "sayhello method end!");     }} where. The Logger class and level enumeration code is as follows:logger.java package sinosoft.dj.aop.staticaop;  import  java.util.date;  public class logger{     /** *//**       *  logging by level       *  @param  level       *  @param  context     */     public statIc void logging (Level level, string context)  {         if  (Level.equals (level.info))  {             system.out.println (New date (). toLocaleString ()  +     +  Context);       }       if  ( Level.equals (level.debuge))  {             System.err.println (New date ()  +  " "  + context);        }   }}level.javapackage sinosoft.dj.aop.staticaop;public enum level  {    info,debuge;} Let's go write a test class and see the code below:test.javapackage sinosoft.dj.aop.staticaop;public class test {     public static void main (String[] args)  {   &NBSp;    ihello hello = new helloproxy (New Hello ());         hello.sayhello ("Doublej");     } run the above code and we can get the following result: Tue  mar 04 20:57:12 cst 2008 sayhello method start. hello doublej2008-3-4 20:57:12 sayhello method end!

From the code above, we can see that the Hello object was created by Helloproxy this so-called proxy state. So,
If we want to remove the logging function later, we just change the code that gets the Hello object to the following:
Package SINOSOFT.DJ.AOP.STATICAOP;

public class Test {
public static void Main (string[] args) {
Ihello Hello = new Hello ();
Hello.sayhello ("Doublej");
}
}

The above code can be said to be the simplest implementation of AOP!
But we'll find a problem, if we have a lot of classes like Hello, are we going to write a lot of helloproxy like that?
Yes, it is. In fact, it is a very troublesome thing. After jdk1.3. The JDK provides us with an 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.

Similarly, we write a Ihello interface and a Hello implementation class. In the interface. We define two methods; The code is as follows:

ihello.java package sinosoft.dj.aop.proxyaop;  public interface ihello {      /** *//**     *  Business Process a method       *  @param  name     */     void  SayHello (String name);     /** *//**     *  Business Process B methods      *  @param  name     */     void saygoogbye (string name);} hello.java  package sinosoft.dj.aop.proxyaop;  public class hello  Implements ihello {      public void sayhello (String  Name)  {         system.out.println ("Hello "  +  name);     }     public void saygoogbYe (string name)  {         system.out.println (name+ "  goodbye! ");     } 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:  package  sinosoft.dj.aop.proxyaop;  import java.lang.reflect.InvocationHandler; import  java.lang.reflect.method; import java.lang.reflect.proxy;  public class  dynaproxyhello implements invocationhandler {      /** *//**      *  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)      */     private Object delegate;    /** *//**      *  Dynamic Generation method After the object is processed   (fixed)      *       *  @param  delegate     *  @param  proxy      *&nbSP; @return     */    public object bind (Object delegate)  {       this.delegate = delegate;         return proxy.newproxyinstance (                 this.delegate.getclass (). getClassLoader (),  this.delegate                         .getclass (). Getinterfaces (),  this);    }     /** *//**     *  each method in the object to be processed is sent by this method to the JVM call, i.e., The method to handle the object can only be called by this method      *  This method is dynamic, not manually called      */    public object invoke (Object proxy, method method, object[] args )       &NBsp;     throws throwable {         object result = null;        try {             //logging before executing the original method             logger.logging (Level.debuge, method.getname ()  +  "  Method start! ");                          //JVM executes the original method through this statement (reflection mechanism)              result = method.invoke (This.delegate, args);     Log logs after         //executes the original method              logger.logging (Level.info, method.getname ()  +  " Method  end . ");         } catch  (exception e)  {             e.printstacktrace ();         }        //return method return value to caller          return result;    }} The logger class and level enumeration that appear in the above class are the same as the implementation of the previous example. There is no code to be posted here. Let's write a test class and try it out. The code is as follows:test.java package  Sinosoft.dj.aop.proxyaop;  public class test {     public  static void main (String[] args)  {          IHello hello =  (Ihello) New dynaproxyhello (). Bind (New hello ());          hello.saygoogbye ("Double j");          hello.sayhello ("Double j");               }} 

The result of running the output is as follows:
Tue may 23:47:30 CST saygoogbye Method start!
Double J goodbye!
2010-5-11 23:47:30 saygoogbye Method end.
Tue may 23:47:30 CST SayHello Method start!
Hello Double J
2010-5-11 23:47:30 sayHello Method end.

    from the above example we see. As long as you are programming with interface-oriented, 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 object being proxied. But we found another problem, This Dynapoxyhello object can only be added to the logging operation before and after the method. Can we decouple the Dynapoxyhello object from the Log Manipulation object (Logger)? The

result is positive. Let's analyze our needs.

We want to add the log operation code (or code of other operations) before or after the method of the Proxied object,
then we can abstract an interface that has only two methods, one that executes before the proxy object executes the method, which we named Start, The second method is the one that executes after the proxy object executes the method, which we named end. The interface is defined as follows:

package sinosoft.dj.aop.proxyaop; import java.lang.reflect.method;  public  interface ioperation {     /** *//**       *  How to do before you do       *  @param  method       */    void start (Method method);     /** *// Actions after the **     *  method is executed      *  @param  method      */    void end (Method method);} 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.javapackage 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 method)  {         logger.logging (Level.info, method.getname ()  +  "  Method start! ");    &NBSP}} Then we'll change the code in the proxy object Dynaproxyhello. The following: package sinosoft.dj.aop.proxyaop;   import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import  java.lang.reflect.Proxy;  public class DynaProxyHello implements  invocationhandler {     /** *//**      *   Operators      */    private Object proxy;     /** *//**     *  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)       */    private object delegate;    /** *//**     *  objects that are processed by the dynamic generation method   (fixed)      *      *  @param  delegate      *  @param  proxy     *  @return       */    public object bind (object delegate,object  Proxy)  {                 this.proxy = proxy;        this.delegate =  Delegate;        return proxy.newproxyinstance (                 this.delegate.getclass (). getClassLoader (), this.delegate                          .getclass (). Getinterfaces (),  this);    }    /** *//**     *  each method in the object to be processed is sent by this method to the JVM call, i.e., The method to handle the object can only be called by this method      *  This method is dynamic, not manually called      */     public object invoke (object proxy, method method, object[]  args)             throws Throwable  {        object result = null;         try {            // Reflection gets an instance of the operator             class clazz =  this.proxy.getclass ();             // Reflection gets operator's Start method             method start = clazz.getdeclaredmethod ("Start",                      new class[] { method.class });             //reflection executes the Start method             start.invoke ( this.proxy, new object[] { method });             //execute the original method to process the object              Result = method.invoke (This.delegate, args);//              reflection Gets the operator's End method              Method end = clazz.getdeclaredmethod ("End",                     new class[] { method.class });//              Reflection Execute End Method              end.invoke (this.proxy, new object[] {  method });        } catch  (Exception e)  {             e.printstacktrace ();         }        return result;     } and then we change the code in the Test.java. Test it: package sinosoft.dj.aop.proxyaop;public class test  {    public static void main (String[] args)  {      IHello hello =  (Ihello) 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 (Level.debuge, Method.getname () + "method end.");
}

public void Start (method 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.


Reflection implements AOP Dynamic Proxy mode (Spring AOP 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.