Several ways of dynamic proxy

The interception function of AOP is realized by the dynamic proxy in java. To put it bluntly, it is to add aspect logic on the basis of the target class to generate an enhanced target class (the aspect logic is executed either before the target class function is executed, or after the target class function is executed, or when the target class function throws an exception. Different. The cut-in timing corresponds to different types of Interceptor, such as BeforeAdviseInterceptor, AfterAdviseInterceptor and ThrowsAdviseInterceptor, etc.).

 

So how does the dynamic proxy implement the weaving of the aspect logic (advise) into the target class method? Below we will introduce and implement the two dynamic proxies used in AOP in detail.

Two dynamic proxies are used in the source code of AOP to implement the interception function: jdk dynamic proxy and cglib dynamic proxy. Both methods exist at the same time, each with advantages and disadvantages. The jdk dynamic proxy is implemented by the reflection mechanism inside java, and the bottom layer of the cglib dynamic proxy is implemented by asm. In general, the reflection mechanism is more efficient in the process of generating classes, while asm is more efficient in the related execution process after the class is generated (the class generated by asm can be cached to solve the problem of inefficiency in the asm generation process) . Another point that must be noted: the prerequisite for the application of jdk dynamic proxy must be that the target class is based on a unified interface. Without the above premise, jdk dynamic proxy cannot be applied. It can be seen that the jdk dynamic proxy has certain limitations. The dynamic proxy implemented by the third-party class library such as cglib is more widely used and has more advantages in efficiency. .

1. Define the interface and implementation

 

[java] view plain copy

  1. package com.meituan.hyt.test3.service;  
  2.   
  3.   
  4. public interface UserService {  
  5.     public String getName(int id);  
  6.   
  7.     public Integer getAge(int id);  
  8. }  

 

 

 

[java] view plain copy

  1. package com.meituan.hyt.test3.service.impl;  
  2.   
  3. import com.meituan.hyt.test3.service.UserService;  
  4.   
  5.   
  6. public class UserServiceImpl implements UserService {  
  7.     @Override  
  8.     public String getName(int id) {  
  9.         System.out.println("------getName------");  
  10.         return "Tom";  
  11.     }  
  12.   
  13.     @Override  
  14.     public Integer getAge(int id) {  
  15.         System.out.println("------getAge------");  
  16.         return 10;  
  17.     }  
  18. }  

 

 

2, jdk dynamic proxy implementation

[java] view plain copy

  1. package com.meituan.hyt.test3.jdk;  
  2.   
  3. import java.lang.reflect.InvocationHandler;    
  4. import java.lang.reflect.Method;  
  5.   
  6. public class MyInvocationHandler implements InvocationHandler {    
  7.     private Object target; //Since we want to proxy, we must know who we are proxying for, and the obj here is the proxy.   
  8.     
  9.     MyInvocationHandler() {    
  10.         super();    
  11.     }    
  12.     
  13.     MyInvocationHandler(Object target) {    
  14.         super();    
  15.         this.target = target;    
  16.     }    
  17.     
  18.     //Then there are three parameters of invoke, the first parameter is the agent, if you want to do some operations on the agent, you can use this parameter; the second is the method to be executed, and the third is the method required to execute the method parameter.  
  19.     @Override    
  20.     public Object invoke(Object o, Method method, Object[] args) throws Throwable { //Write all the operations we want to append to the proxy through the proxy in the invoke method  
  21.         if("getName".equals(method.getName())){    
  22.             System.out.println("++++++before " + method.getName() + "++++++");    
  23.             Object result = method.invoke(target, args);    
  24.             System.out.println("++++++after " + method.getName() + "++++++");    
  25.             return result;    
  26.         }else{    
  27.             Object result = method.invoke(target, args);    
  28.             return result;    
  29.         }    
  30.     
  31.     }    
  32. }    


[java] view plain copy

  1. package com.meituan.hyt.test3.jdk;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Proxy;  
  5.   
  6. import com.meituan.hyt.test3.service.UserService;  
  7. import com.meituan.hyt.test3.service.impl.UserServiceImpl;  
  8.   
  9. public class Main1 {  
  10.      public static void main(String[] args) {    
  11.            
  12.         UserService userService = new UserServiceImpl();    
  13.         //Create an InvocationHandler that describes what we want the agent to do  
  14.         InvocationHandler invocationHandler = new MyInvocationHandler(userService);   
  15.         //Create a real proxy through the InvocationHandler just created. The first parameter is the class loader, and the second parameter is which interface the proxy implements (the same interface as the proxy implements)  
  16.         UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),    
  17.                 userService.getClass().getInterfaces(), invocationHandler);    
  18.         System.out.println(userServiceProxy.getName(1));    
  19.         System.out.println(userServiceProxy.getAge(1));    
  20.     }    
  21. }  


 

operation result

 

++++++before getName++++++
------getName------
++++++after getName++++++
Tom
------getAge------
10

3, cglib dynamic proxy implementation

Cglib is an excellent dynamic proxy framework. Its bottom layer uses ASM to dynamically generate subclasses of the proxied class in memory. Using CGLIB, even if the proxy class does not implement any interface, the dynamic proxy function can be implemented. CGLIB is easy to use, and it runs much faster than JDK's Proxy dynamic proxy:

CGLIB's core class:
    net.sf.cglib.proxy.Enhancer - the main enhancement class
    net.sf.cglib.proxy.MethodInterceptor - The main method interception class, which is a sub-interface of the Callback interface, requires the user to implement
    net.sf.cglib.proxy.MethodProxy – the proxy class of the java.lang.reflect.Method class of the JDK, which can easily implement the method of the source object. Call, such as use:
    Object o = methodProxy.invokeSuper(proxy, args);//Although the first parameter is the proxy object, there will be no infinite loop problem.

The net.sf.cglib.proxy.MethodInterceptor interface is the most common callback type and is often used by proxy-based AOP to intercept method calls. This interface only defines one method
public Object intercept(Object object, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable;

The first parameter is the proxy object, and the second and third parameters are the intercepted method and method parameters, respectively. The original method may be invoked by normal reflection using the java.lang.reflect.Method object, or by using the net.sf.cglib.proxy.MethodProxy object. net.sf.cglib.proxy.MethodProxy is usually preferred because it is faster.

 

[java] view plain copy

  1. package com.meituan.hyt.test3.cglib;  
  2.   
  3.   
  4. import net.sf.cglib.proxy.MethodInterceptor;  
  5. import net.sf.cglib.proxy.MethodProxy;  
  6.   
  7. import java.lang.reflect.Method;  
  8.   
  9.   
  10. public class CglibProxy implements MethodInterceptor { //The main method interception class, which is a sub-interface of the Callback interface, needs to be implemented by the user
  11.     @Override  
  12.     public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  13.         System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");  
  14.         System.out.println(method.getName());  
  15.         Object o1 = methodProxy.invokeSuper(o, args);  
  16.         System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");  
  17.         return o1;  
  18.     }  
  19. }  

[java] view plain copy

  1. package com.meituan.hyt.test3.cglib;  
  2.   
  3. import com.meituan.hyt.test3.service.UserService;    
  4. import com.meituan.hyt.test3.service.impl.UserServiceImpl;    
  5. import net.sf.cglib.proxy.Enhancer;   
  6. public class Main2 {  
  7.      public static void main(String[] args) {    
  8.             CglibProxy cglibProxy = new CglibProxy();    
  9.         
  10.             Enhancer enhancer = new Enhancer(); //The main enhancement class  
  11.             enhancer.setSuperclass(UserServiceImpl.class); //Set the parent class, the enhanced class  
  12.             enhancer.setCallback(cglibProxy); //callback object  
  13.         
  14.             UserService o = (UserService)enhancer.create();//Use cglibProxy to enhance UserServiceImpl    
  15.             o.getName(1);    
  16.             o.getAge(1);    
  17.         }    
  18. }  



operation result:

 

++++++before CGLIB$getName$0++++++
getName
------getName------
++++++before CGLIB$getName$0++++++
++++++before CGLIB$getAge$1++++++
getAge
------getAge------
++++++before CGLIB$getAge$1++++++

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325194903&siteId=291194637
Recommended