The implementation of the AOP dynamic Proxy mode (SPRINGAOP implementation principle) by reflection

Source: Internet
Author: User
Tags aop bind reflection throwable

I haven't used spring for a long time. Suddenly picked up the book. I found myself unfamiliar with AOP.
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 solutions to problem solving, 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 get some way to 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 {
    /**
     * 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.

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!");

    }

}

which. The logger class and level enumeration code is as follows:
Logger.java

Package SINOSOFT.DJ.AOP.STATICAOP;

Import java.util.Date;

public class logger{
    /**
    * Log by rank *
     @param level
    * @param context */public
    static void Logging (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.java

Package SINOSOFT.DJ.AOP.STATICAOP;

Public enum level {
    info,debuge;
}

Let's write a test class and see the code below:
Test.java

Package SINOSOFT.DJ.AOP.STATICAOP;

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

Running the above code 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 the helloproxy of this so-called proxy state. So, if we want to remove the logging function later. So 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 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. 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 method
     * @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); c16/>} 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 {/** * 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;  /** * The object that is processed by the dynamic generation method (fixed) * * @param delegate * @param proxy * @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, that is, the method of the object to be processed can only be called by this method * This method is dynamic, not manually called */public Object Invoke (O
        Bject Proxy, method method, object[] args) throws Throwable {Object result = null; try {//Execute the original method before logging logger.logging (Level.debuge, Method.getname () + "method end.");
            The JVM executes the original method through this statement (reflection mechanism) result = Method.invoke (this.delegate, args);
        Log logger.logging (Level.info, Method.getname () + "method start!") after the original method is executed;
        } catch (Exception e) {e.printstacktrace ();
    }//Return method return value to caller return result; }

}

The logger class and level enumeration appearing in the above class are the same as the implementation of the previous example. No code is posted here.

Let's write a test class to 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 Mar 21:24:03 CST 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 object being proxied. But we found another problem, This Dynapoxyhello object can only follow us to the operation of adding a log record to the method. Can we decouple the Dynapoxyhello object from the Log Manipulation object (Logger)?
The result is yes. Let's analyze our needs.
We are going to add the log operation code (or the code of the other operation) before or after the method of the proxy object.
So, we can abstract an interface, this interface only two methods, one is executed before the proxy object to execute the method, we named start, the second method is executed after the proxy object execution method, we named end. The interface is defined as follows:

Package SINOSOFT.DJ.AOP.PROXYAOP;

Import Java.lang.reflect.Method;

Public interface IOperation {
    /**
     * method to perform previous operation
     * @param method
      *
    /Void Start (method);
    /**
     * action after execution
     * @param method *
    /Void End (Approach method);

Let's write a class that implements the above interface. We take it as his 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:

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 {/** * operator */private Object proxy;

    /** * 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;  /** * The object that is 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, that is, the method of the object to be processed can only be called by this method * This method is dynamic, not manually invoked */Public Object Invoke (
       Object Proxy, method, object[] args) throws Throwable {object result = NULL;
         try {   The reflection gets the instance of the operator Class clazz = This.proxy.getClass (); The reflection gets the operator's Start method, start = Clazz.getdeclaredmethod ("Start", new class[] {METHOD.CLA
            SS});
            Reflection execution Start Method Start.invoke (This.proxy, new object[] {method});
Executes the original method to process the object result = Method.invoke (this.delegate, args); The reflection Gets the end method of the operator methods end = Clazz.getdeclaredmethod ("End", new class[] {Metho
D.class});

        Reflection execution End Method End.invoke (This.proxy, new object[] {method});
        } catch (Exception e) {e.printstacktrace ();
    } return result; }

}

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) {
        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. I understand.

It feels like a decoupled process compared to a dynamic agent.

What is the first aspect-oriented programming?
It means separating the logic code from the code that handles trivial transactions so that the complexity can be detached.
Let people at the same time only think about code logic, or trivial matters.
Code logic such as inserting a piece of data, the trivial transaction involves getting the connection and closing the connection, starting the transaction, and committing the transaction.
A tangent is a logical code in a large heap of trivial transactions.

And then for example:
Let's say you have a piece of logic code to write ~ Write log before this code, write log after the code is finished. The result is a whole bunch of log code that drowns out the logic code.
The idea of AOP is to extract the non-logical part of the code, just consider the logic code on the line, I draw the box, here write the previous log, here to write the logic, here write the log behind.
Actually, I didn't use it. Logical code seems to be separate from non-logical code in different files. Personally feel that jumping files is also very irritable.
The feeling should be that the system to a certain extent will require so strict complexity control it.

Although I didn't use it, I suddenly thought I had seen it in a certain system. This is the system, using AOP, the transaction management of the database Ah what is the seal. However, the log statement for this system is not sealed, and the logic code is surrounded by statements such as Logger.log ("xxxxx"). If you say a function, maybe half is doing log, and half of a class is doing log. Even if the frame is drawn to an AOP, there are ways to use it or not.

In fact, without the framework of AOP, you can also take the front and back of the trivial matters of their own abstraction can also be separated, although not the framework but also has the meaning of AOP, the trivial transactions are compressed into a pre-function and a post-function inside. More related information

Http://www.importnew.com/15420.html

http://www.iteye.com/topic/1116696

https://www.zhihu.com/question/24863332
Very good

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.