The underlying implementation technology of Spring AOP Proxy Invocationhandler

Source: Internet
Author: User
Tags aop reflection sleep

AOP Overview

The ultimate goal of the Software programming language is to simulate the world in a more natural and flexible way, from the original machine language to the process language to the object-oriented language, and we see that the programming language is stepping through a more natural and powerful way of describing the software. AOP is a leap in the concept of software development, the introduction of AOP will effectively compensate for the shortcomings of OOP, OOP and AOP respectively from the vertical and horizontal software abstraction, effectively eliminate repetitive code, so that the code in a more elegant and more efficient way to express the logic.

AOP has three ways to implant slices: one is the compile-time weaving, which requires the use of a special Java compiler, ASPECTJ is the representative, and the other is the class loading phase weaving, which requires the use of special class loaders, ASPECTJ and Aspectwerkz are the representatives of the , the third is the dynamic agent weaving, in the run-time for the target class to add the way to enhance the generation of subclasses, Spring AOP with dynamic agent weaving facets.

Spring AOP uses two kinds of proxy mechanisms, one is a dynamic agent based on the JDK, the other is a dynamic agent based on Cglib, and two agent mechanisms are needed, largely because the JDK itself only provides an interface-based proxy and does not support the proxy of the class.

JDK-based agents and Cglib-based proxies are the core implementations of Spring AOP, and understanding these two agent technologies helps to explore the implementation mechanism of spring AOP. You can even throw away spring to provide your own AOP implementations as long as you want.

Instances with cross-cutting logic

First, let's look at a repetitive code logic that cannot be abstracted through OOP, which is the main object of the AOP transformation. Below, we understand crosscutting logic through an instance of a business method Performance Monitor. Business method performance monitoring, which starts monitoring before each business method call, ends monitoring and gives performance reports when the business method ends:

Code Listing 2 Forumservice: including performance monitoring crosscutting code

Package com.baobaotao.proxy; public class Forumserviceimpl implements Forumservice ... {

public void removetopic (int topicid) ...   {//Start performance monitoring Performancemonitor.begin ("com.baobaotao.proxy.ForumServiceImpl.removeTopic");   SYSTEM.OUT.PRINTLN ("Simulated deletion of topic records:" +topicid); Try ...   {Thread.CurrentThread (). Sleep (20); } catch (Exception e) ...   {throw new RuntimeException (e);  }//End monitoring, and give performance report information Performancemonitor.end (); }

public void Removeforum (int forumid) ...   {//Start performance monitoring Performancemonitor.begin ("Com.baobaotao.proxy.ForumServiceImpl.removeForum");   SYSTEM.OUT.PRINTLN ("Simulated Delete forum record:" +forumid); Try ...   {Thread.CurrentThread (). Sleep (40); } catch (Exception e) ...   {throw new RuntimeException (e);  }//End monitoring, and give performance report information Performancemonitor.end (); } }

The code in bold in Listing 2 is code that has crosscutting characteristics, and you need to add similar performance monitoring statements before and after each business method that requires performance monitoring.

We guarantee the integrity of the instance, we provide a very simple performance monitoring implementation class, as shown in Listing 3 of the code:

Code Listing 3 PerformanceMonitor

Package com.baobaotao.proxy;

public class PerformanceMonitor {//Save thread-related performance monitoring information through a ThreadLocal private static threadlocal<methodperformace> PE  Rformacerecord = new threadlocal<methodperformace> ();   public static void Begin (String method) {System.out.println ("Begin monitor ...");   Methodperformace MP = new Methodperformace (method);  Performacerecord.set (MP);   public static void End () {SYSTEM.OUT.PRINTLN ("End monitor ...");   Methodperformace MP = Performacerecord.get (); Mp.printperformace (); Print out information on business method performance monitoring}}

PerformanceMonitor provides two methods, the Begin method begins the monitoring of a business class method, which is the signature of the business method, and the end () method ends the monitoring of the business method and gives information about performance monitoring. Since each business method has to record performance monitoring data separately, we use threadlocal,threadlocal as a magic weapon to cut off the thread-safe state. The elements in Threadlocal are the method performance Record object Methodperformace, and its code is as follows:

Code Listing 4 Methodperformace

Package com.baobaotao.proxy;  public class Methodperformace {private long begin;  private long end;     Private String Servicemethod;        Public Methodperformace (String servicemethod) {this.servicemethod = Servicemethod; This.begin = System.currenttimemillis ();//Record the system time at the beginning of the method call} public void Printperformace () {//The following two lines of program get after method call         The system time is calculated and the method execution takes time to end = System.currenttimemillis ();         Long elapse = End-begin; Reporting the business method execution time System.out.println (servicemethod+ "spends" +elapse+ "milliseconds.     "); } }

#p #

Test this business method that has the method performance monitoring capability by using the following code:

Package com.baobaotao.proxy; public class Testforumservice {public static void main (string[] args) {Forumservice forumservice = new Forumser         Viceimpl ();     Forumservice. Removeforum (10);  Forumservice. Removetopic (1012); } }

We get the following output information:

Begin Monitor ... Simulated Delete Forum record: Com.baobaotao.proxy.ForumServiceImpl.removeForum takes 47 milliseconds to monitor ...

Begin Monitor ... Analog Delete topic record: 1012 End Monitor ... com.baobaotao.proxy.ForumServiceImpl.removeTopic takes 16 milliseconds.

As the example shows, to perform performance monitoring on a business class, you must add repetitive code to turn on performance monitoring and end performance monitoring both before and after each business class method. The performance monitoring code for these non-business logic undermines the purity of Forumserviceimpl as a business class. Below, we separate the JDK dynamic agent and the Cglib Dynamic Agent technology, removing these crosscutting code from the business class to enable and end performance monitoring in the business approach.

JDK Dynamic Agent

The dynamic agent technology is provided after JDK 1.3, allowing the developer to create proxy instances of the interface at run time. When Sun just launched its dynamic agent, it was hard to imagine how much it would actually do, and now we finally find that dynamic proxies are the perfect bottom-up technology for AOP.

The dynamic agent of the JDK mainly involves the two classes in the Java.lang.reflect package: Proxy and Invocationhandler. Where Invocationhandler is an interface that can define crosscutting logic by implementing the interface, and invoke the code of the target class through the reflection mechanism to dynamically weave the crosscutting logic and the business logic together.

The proxy for the Invocationhandler implementation class dynamically creates a broker instance that conforms to an interface. This must be very abstract, we immediately began to use proxy and invocationhandler these two magic rings the performance monitoring code in the previous section of the AOP-style transformation.

First, we remove the crosscutting code for performance monitoring from the business class Forumserviceimpl, so that Forumserviceimpl is only responsible for the specific business logic, as shown in:

Code Listing 5 Forumserviceimpl: Removing performance monitoring crosscutting code

 

Package Com.baobaotao.proxy, public class Forumserviceimpl implements Foru Mservice { public void removetopic (int topicid) {        ①  System . OUT.PRINTLN ("Simulated deletion of topic records:" +topicid);   try {   thread.currentthread (). Sleep ()  } catch (Exception e) {   throw new Runtimee Xception (e);  }   ② }  public void Removeforum (int forumid) {       & nbsp ①  System.out.println ("Simulated Delete forum record:" +forumid);   try {   thread.currentthread (). Sleep (+)  } catch (Exception e) {   throw new Runtimee Xception (e);  }         ② }

In code Listing 5, ① and ②, the original performance monitoring code was removed, and we kept only the real business logic.

Crosscutting code removed from the business class of course we have to find a place to stay, Invocationhandler is the homeland of the crosscutting code, and we place the code for performance monitoring in Performacehandler, as shown in Listing 6:

Code Listing 6 Performacehandler

Package com.baobaotao.proxy; Import Java.lang.reflect.InvocationHandler; Import Java.lang.reflect.Method;

public class Performacehandler implements Invocationhandler {private Object target;  Public Performacehandler (object target) {//①target is the target business class this.target = target; public object invoke (object proxy, Method method, object[] args) throws Throwable {Performancemonitor.begin (targe T.getclass (). GetName () + "."   + Method.getname ());   Object obj = Method.invoke (target, args);//② calls the business method of the Target business class Performancemonitor.end () through the reflection method;  return obj; } }

The code for the Bold section is the crosscutting code for performance monitoring, and we find that the crosscutting code appears only once, not the original. Attention is paid to the Method.invoke () at ②, which invokes the method of the target object through a reflection mechanism, so that the Invocationhandler invoke (object proxy, method, object[] args) Method weaves the Crosscutting code and the target business class code together, so we can consider Invocationhandler as a weaver of business logic and crosscutting logic. Let's take a closer note of this piece of code.

#p #

First, we implement the Invocationhandler interface, which defines a method for invoke (Object Proxy, method, object[] args), which is a proxy instance and is not typically used The method is a way on the proxy instance that can initiate a reflection call to the target class, which is used by the method arguments passed in by the proxy class when the reflection is invoked.

In addition, we pass the target in the constructor to the real target object, as shown in ①, in the interface method invoke (Object proxy, method, object[] args), the object class instance is passed to Method.invoke () Method that invokes the target class method through reflection, as shown in ②.

Below, we create a proxy instance of the Forumservice interface by using Proxy with Performacehandler, as shown in Listing 7:

Code Listing 7 Testforumservice: Creating a proxy instance

 

Package com.baobaotao.proxy; import java.lang.reflect.Proxy; public class Testforumservice { public static void main (string[] args) {  Forumservice target = new Forumserviceimpl ();//① Business class//② weaves the target business class and the crosscutting code together   Performacehandler handler = new Performacehandler (target);         //③ creates proxy classes for handler that weave the target business class logic and performance monitoring crosscutting logic   Forumservice proxy = ( Forumservice) Proxy.newproxyinstance (Target.getclass (). getClassLoader (),     Target.getclass (). Getinterfaces (),  handler);         //④ Operation Agent Example   Proxy.removeforum (10);   Proxy.removetopic (1012);  }}

The code above completes the work of Business class code and cross-cutting code weaving and interface broker instance generation, where at ② we weave the Forumservice instance into a Performacehandler instance that contains the performance monitoring logic, and then at ③, The static method of proxy newproxyinstance () creates a proxy instance of the Forumservice interface for handler that incorporates the business class logic and performance monitoring logic, and the first entry of the method is the class loader, The second entry is a set of interfaces to be implemented by the proxy instance that is created, and the third parameter is the Braid object that consolidates the business logic and the crosscutting logic.

According to ③, this proxy instance implements all the interfaces of the target business class, that is, the Forumserviceimpl Forumservice interface. This allows us to invoke the proxy instance in the same way that an instance of the Forumservice interface is called, as shown in ④. Run the above code and output the following information:

Begin Monitor ... Simulated Delete Forum record: Com.baobaotao.proxy.ForumServiceImpl.removeForum takes 47 milliseconds to monitor ...

Begin Monitor ... Analog Delete topic record: 1012 End Monitor ... com.baobaotao.proxy.ForumServiceImpl.removeTopic takes 26 milliseconds.

We found that the effect of the program was consistent with writing performance monitoring logic directly in the business class, but here the original scattered crosscutting logic code has been extracted into the performacehandler. When the business methods of other business classes (such as UserService, Systemservice, etc.) also need to use performance monitoring, we just have to create proxy objects for each of them in the same way. Below, we describe the invocation relationship with a time series diagram and further the nature of the proxy instance, as shown in Figure 1:



Figure 1: Timing diagram of the proxy instance

We highlight the Forumservice instance created by the agent using the dashed shadow in the figure above, which integrates crosscutting logic and business logic internally using Performacehandler. When the caller invokes the Removeforum () and Removetopic () methods of the proxy object, the internal invocation timing of the above diagram clearly tells us what actually happened.

Cglib Dynamic Agent

There is a limitation to using the JDK to create an agent, that is, it can only create proxies for interfaces, which we newproxyinstance from the interface method of proxy (ClassLoader loader, class[] interfaces, Invocationhandler h) It is clear that the third entry interfaces is the implementation interface specified for the proxy instance. While interface-oriented programming has been admired by many influential people, including Rod Johnson, developers have encountered a lot of confusion in actual development: Is it really necessary to operate a simple business table to create 5 classes (Domain object class, DAO interface, DAO implementation class, Service Interface and service implementation Class). For this issue, we will leave it to members for further discussion. The question now is: How do you dynamically create a proxy instance for a class that does not have a business method defined through an interface? The JDK's proxy technology is clearly out of the cglib, and as a replacement, it fills the void. You can get the Cglib class package from http://cglib.sourceforge.net/, or you can get the class package directly from spring's associated class library lib/cglib.

#p #

Cglib uses very low-level bytecode technology to create subclasses for a class, and to intercept all calls to the parent class method in subclasses using the techniques of method interception, and to weave the crosscutting logic into the interception method accordingly. Below, we use cglib technology to write a proxy that can create a proxy object for any class that weaves performance-monitoring crosscutting logic, as shown in Listing 8:

Code Listing 8 Cglibproxy

Package com.baobaotao.proxy; Import Java.lang.reflect.Method; Import Net.sf.cglib.proxy.Enhancer; Import Net.sf.cglib.proxy.MethodInterceptor; Import Net.sf.cglib.proxy.MethodProxy;

public class Cglibproxy implements Methodinterceptor {private enhancer enhancer = new enhancer ();   Public Object GetProxy (class Clazz) {Enhancer.setsuperclass (clazz); ① set the Class Enhancer.setcallback (this) that requires the subclass to be created; return Enhancer.create (); ② dynamic creation of subclass instances via bytecode technology} public object intercept (object obj, method, object[] args, Methodproxy proxy) throws Throwa ble {performancemonitor.begin (Obj.getclass (). GetName () + "."   +method.getname ()); Object result=proxy.invokesuper (obj, args);   ③ calls the method Performancemonitor.end () in the parent class through the proxy class;  return result; } }

In the code above, you can create a dynamic proxy object for a class through GetProxy (class Clazz), which is a subclass of the specified class Clazz. In this proxy object, we weave the crosscutting logic of performance monitoring (Bold section). Intercept (Object obj, method, object[] Args,methodproxy proxy) is a method of Cglib defined Inerceptor interface, and obj represents an instance of the parent class. method is the reflection object of the parent class, and args is the dynamic entry of the method, and proxy is the instance of the agent class.

Below, we create a proxy object for the Forumserviceimpl class through Cglibproxy and test the method of the proxy object, as shown in Listing 9:

Code Listing 9 Testforumservice: Testing the proxy class created by Cglib

Package com.baobaotao.proxy; Import Java.lang.reflect.Proxy;    public class Testforumservice {public static void main (string[] args) {Cglibproxy proxy = new Cglibproxy ();    Forumserviceimpl Forumservice =//① Creates a proxy object (Forumserviceimpl) Proxy.getproxy (Forumserviceimpl.class) by dynamically generating subclasses;    Forumservice.removeforum (10);  Forumservice.removetopic (1023); } }

In ①, we created a proxy object that weaves the performance monitoring logic through Cglibproxy for Forumserviceimpl, and invoked the business method of the proxy object. Run the above code and enter the following information:

Begin Monitor ... Simulated Delete forum record: com.baobaotao.proxy.forumserviceimpl$ $EnhancerByCGLIB $$2a9199c0.removeforum takes 47 milliseconds. Begin Monitor ... Analog Delete topic Record: 1023 End monitor ... com.baobaotao.proxy.forumserviceimpl$ $EnhancerByCGLIB $$2a9199c0.removetopic takes 16 milliseconds.

Observing the above output, in addition to the discovery of two business methods are woven into the performance monitoring logic, we also found that the name of the proxy class is com.baobaotao.proxy.forumserviceimpl$ $EnhancerByCGLIB $$2a9199c0, This particular class is the subclass that Cglib is dynamically creating for Forumserviceimpl.

Summary

At the bottom of Spring AOP is the use of the JDK dynamic agent or cglib Dynamic Agent technology to weave the crosscutting logic into the target bean. Here, we make a summary of dynamic creation of proxy objects in the above two sections.

In Performacehandler and Cglibproxy, there are three points to note: First, all the methods of the target class have been added to the performance monitoring crosscutting code, and sometimes this is not what we expected, we might just want to weave the crosscutting code into some methods in the business class; , we manually specify the weaving point that weaves the crosscutting code, which is called before the start and end of the target class business method, and thirdly, we write the crosscutting code manually. The above three issues occupy an important place in AOP, because the main work of Spring AOP is to expand around the three points above: Spring AOP Specifies which methods of the class are applied to the crosscutting logic by Pointcut (tangent). Through advice (enhanced) describes the specific weaving points of the crosscutting logic and methods (before, after the method, the ends of the method, etc.), and spring also combines pointcut and advice through the Advisor (facet). With the information of the advisor, spring can use the dynamic agent technology of the JDK or cglib to create a proxy object for the target bean for the weaving facet.

The proxy object created by the JDK dynamic agent, under JDK 1.3, has a strong performance. While the performance of dynamic proxy objects has been greatly improved in the high-version JDK, studies have shown that the performance of dynamic proxy objects created by Cglib is still much higher (approximately 10 times times) than the performance of the JDK-created proxy objects. While Cglib performance is much slower than the JDK dynamic agent when creating proxy objects (approximately 8 times times), for singleton proxy objects or agents with instance pools, because there is no need to create proxy objects frequently, it is more appropriate to use Cglib dynamic proxy technology, Conversely, it is suitable to use JDK dynamic Agent technology. In addition, the final method in the target class cannot be proxied because Cglib creates a proxy object using techniques that generate subclasses.

Related Article

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.