Reflection implementation AOP Dynamic Proxy mode instance description (Spring AOP implementation principle)

Source: Internet
Author: User
Tags aop reflection throwable

Note that the implementation of Spring AOP is not a dynamic proxy in Java. is in proxy mode and Cglib (code generationlibrary), but now use the ASM framework directly to manipulate bytecode without Cglib (code Generation Library).

I haven't used spring for a long time. Suddenly picked up the book. I found myself unfamiliar with AOP.
AOP, in fact, is about cutting-plane programming.
OO focuses on the way we solve the problem (encapsulated as method), and AOP focuses on many solutions to solve problems in common, is a complement to OO thought!
Or do you take an example that is often cited by others:
For example, there are a lot of business methods in an application that we are going to develop now, but we now have to do a full monitoring or partial monitoring of the implementation of this method. Maybe we'll go ahead and add a log to the method,
Let's write an example to see our simplest solution
We first write an interface Ihello.java code as follows:

Package SINOSOFT.DJ.AOP.STATICAOP;
 
 Public interface Ihello {
     /** *//**
      * Assumes that this is a business method
      * @param name *
     /void SayHello (String name);
 


There is a method for entering the name "Hello" added; 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 that we're going to add a logging business to this business method, what do we do without changing the original code? Perhaps you will write a class to implement the Ihello interface and rely on the class of Hello. 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
Ten public void SayHello (String name) {
One logger.logging (Level.debuge, "SayHello method Start");
Hello.sayhello (name);
Logger.logging (Level.info, "SayHello method end!");
14
15}
16
17}
18
which. 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 log according to the grade
8 * @param level
9 * @param context
10 */
One public static void logging (level level, String context) {
if (Level.equals (Level.info)) {
System.out.println (New Date (). toLocaleString () + "" + context);
14}
if (Level.equals (Level.debuge)) {
System.err.println (New Date () + "" + context);
17}
18}
19
20}
21level.java

1package SINOSOFT.DJ.AOP.STATICAOP;
2
3public enum Level {
4 Info,debuge;
5}
6 Let's go and write a test class to see the code as follows:
Test.java
1package SINOSOFT.DJ.AOP.STATICAOP;
2
3public class Test {
4 public static void main (string[] args) {
5 Ihello Hello = new Helloproxy (new Hello ());
6 Hello.sayhello ("Doublej");
7}
8}
9 Run the above code we can get the following results:

Tue Mar 20:57:12 CST 2008 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. In this way, If we want to get rid of the function of logging in the future, we just need to 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        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're going to find a problem, if we have a lot of classes like Hello, are we going to write a bunch of helloproxy? Yes, Yes, it's also a very troublesome thing. After jdk1.3. JDK has provided us with a api   Java.lang.reflect.InvocationHandler class. This class allows us to dynamically do something about the way the JVM invokes a class's methods. Let's change the code 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
1package SINOSOFT.DJ.AOP.PROXYAOP;
2
3public interface Ihello {
4/** *//**
5 * Business Process a method
6 * @param name
7 */
8 void SayHello (String name);
9/** *//**
10 * Business Process B method
One * @param name
12 */
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 System.out.println (name+ "goodbye!");
10}
11}
12
We're going to write a proxy class just the same. Let this class implement the Java.lang.reflect.InvocationHandler interface with the following code:
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 * Objects to be processed (that is, the object that we want to add the business logic to before and after the method, such as Hello in the example)
11 */
Private Object delegate;
13
14/** *//**
15 * The object to be processed by the dynamic generation method (fixed)
16 *
* @param delegate
@param proxy
* @return
20 */
public object bind (object delegate) {
This.delegate = delegate;
Return Proxy.newproxyinstance (
This.delegate.getClass () getClassLoader (), this.delegate
GetClass (). Getinterfaces (), this);
26}
27/** *//**
28 * Each method in the object to be processed is sent to the JVM call by this method, that is, the method of the object to be processed can only be invoked through this method
29 * This method is dynamic, not manually invoked
30 */
"Public Object Invoke" (object proxy, Method method, object[] args)
Throws Throwable {
Object result = null;
The try {
35//record log before executing the original method
Logger.logging (Level.debuge, Method.getname () + "method end.");
37
//JVM executes the original method (reflection mechanism) through this statement
The result = Method.invoke (this.delegate, args);
40//Record log after the original method is executed
Logger.logging (Level.info, Method.getname () + "method start!");
The ' Catch ' (Exception e) {
E.printstacktrace ();
44}
45//Return method return value to caller
return result;
47}
48
49}
50
The logger class and level enumeration that appear 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 for testing. The code is as follows:
Test.java
1package SINOSOFT.DJ.AOP.PROXYAOP;
2
3public class Test {
4 public static void main (string[] args) {
5 Ihello Hello = (ihello) new Dynaproxyhello (). bind (New Hello ());
6 Hello.saygoogbye ("Double J");
7 Hello.sayhello ("Double J");
8
9}
10}
11
The results of running the output are as follows:
Tue Mar 21:24:03 CST 2008 Saygoogbye method end.
Double J goodbye!
2008-3-4 21:24:03 Saygoogbye Method start!
Tue Mar 21:24:03 CST 2008 SayHello method end.
Hello Double J
2008-3-4 21:24:03 SayHello Method start!
Because of the thread's relationship, the second method begins to appear before the end of the first method. This is not our concern!
From the example above we can see that. As long as you are using interface-oriented programming, then any of your object's methods should be added before the operation of logging. He (Dynapoxyhello) automatically goes to the agent to execute every method in the proxy object (Hello), A Java.lang.reflect.InvocationHandler interface will be our proxy object and the object is decoupled. However, we also found that there is a problem, This Dynapoxyhello object can only be followed by the operation of logging before and after the method. Can we get the Dynapoxyhello object and the log Operation object (Logger) to be decoupled?
The result is yes. Let's analyze our needs.
We want to add the log operation code (or other code of operation) to the method of the proxy object before or after it.
Well, we can abstract an interface in which there are only two methods, one that executes before the proxy object executes the method, we name start, and the second method, which executes after the method is executed by the proxy object, is 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
8 * @param method
9 */
A void Start (method method);
11/** *//**
12 * Action After the method is executed
@param method
14 */
void End (method method);
16}
17
Let's write a class that implements the interface above. We make him the real operator, as follows 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 method) {
Logger.logging (Level.info, Method.getname () + "method start!");
}

}

Then we'll 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 * operator
10 */
One private Object proxy;
12/** *//**
13 * Objects to be processed (that is, the object that we want to add the business logic to before and after the method, such as Hello in the example)
14 */
Private Object delegate;
16
17/** *//**
18 * The object to be processed by the dynamic generation method (fixed)
19 *
* @param delegate
* @param proxy
* @return
23 */
public object bind (Object Delegate,object proxy) {
25
This.proxy = proxy;
This.delegate = delegate;
Return Proxy.newproxyinstance (
This.delegate.getClass () getClassLoader (), this.delegate
GetClass (). Getinterfaces (), this);
31}
32/** *//**
33 * Each method in the object to be processed is sent to the JVM call by this method, that is, the method of the object to be processed can only be invoked through this method
34 * This method is dynamic, not manually invoked
35 */
The public object invoke (Object Proxy, Method method, object[] args)
Notoginseng throws Throwable {
Object result = null;
The try {
40//Reflection Gets the operator's example
The Class clazz = This.proxy.getClass ();
42//reflect the operator's Start method
The method start = Clazz.getdeclaredmethod ("Start"),
New class[] {method.class});
45//Reflection Execution Start method
Start.invoke (This.proxy, new object[] {method});
47//Execute the original method of the object to be processed
result = Method.invoke (this.delegate, args);
49//reflection Gets the operator's End method
Method end = Clazz.getdeclaredmethod (' End '),
Wuyi New class[] {method.class});
52//Reflection Execution End method
End.invoke (This.proxy, new object[] {method});
54
+} catch (Exception e) {
E.printstacktrace ();
57}
return to result;
59}
60
61}
62
Then we'll change the code in the Test.java. Test:

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 a log record before each method, but not the method, add the log record. 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 will the agents and operators to solve the lotus root!

Here is a question for everyone, if we do not want to let all methods are logged, we should how to solve the lotus root.
My idea is to add an if () to the proxy object's public objects invoke (object Proxy, method methods, object[] args), and to judge the name of the pass in. The condition of the judgment exists within the XML. So we can configure the file to solve the Lotus root. If interested friends can put the operator, the agent, through the configuration file configuration, then you can write a simple SPRINGAOP framework.

Some concepts of Spring AOP

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

Slice (Aspect): A modular focus that may cross multiple objects. Transaction management is a good example of crosscutting concerns in Java application. In spring AOP, slices can be implemented using common classes (style based on patterns) or @aspect annotations (@AspectJ style) in ordinary classes.

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

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

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

Introduction (Introduction): (also known as an internal type declaration (Inter-type declaration)). Declare an extra method or a field of a type. Spring allows the introduction of a new interface (and a corresponding implementation) to any object that is being represented. For example, you can use an introduction to enable the bean to implement the IsModified interface to simplify caching mechanisms.

Target object: An object that is notified (advise) by one or more slices (aspect). It is also referred to as the object of being notified (advised). Since spring AOP is implemented through Run-time proxies, this object is always a proxy (proxied) object.

AOP Proxy: An object created by the AOP framework that implements the facet contract (aspect contract) (including functions such as notification method execution). In spring, an AOP agent can be either a JDK dynamic proxy or a cglib proxy. Note: Spring 2.0 recently introduced a schema-based-style and @aspectj annotation-style facet declaration, which is transparent for users who use these styles.

Weaving (weaving): Connecting slices (aspect) to other application types or objects, and creating an object to be notified (advised). These can be done at compile time (for example, using the ASPECTJ compiler), when the class is loaded, and at run time. Spring, like other pure Java AOP frameworks, completes weaving at run time.

Type of notification:

Forward notification (before advice): a notification that executes before a join 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 to be executed after a connection point (join points) completes normally: for example, a method does not throw any exceptions and returns normally.

Notification after an exception is thrown (after throwing advice): a notification that executes when the method throws an exception exit.

After (finally) advice: notification to be executed when a connection point exits (whether it is a normal return or an exception exit).

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

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.