Discussion on Java agents of jdk static agents dynamic agents and cglib dynamic agents

  • 2020-06-01 09:51:48
  • OfStack

1. Proxy is a common design pattern of Java. The proxy class calls the relevant methods of the proxied class and enhances the related methods. Add some non-business code, such as transaction, log, alarm and email.

2. jdk static proxy

1. Business interface


/** 
 *  Business interface  
 * @author pc 
 * 
 */
public interface UserService { 
   
  //  increase 1 A user  
  public void addUser(); 
  //  Edit account  
  public void editUser(); 
 
} 

2. Business implementation class


/** 
 *  Business implementation class  
 * @author pc 
 * 
 */
public class UserServiceImpl implements UserService { 
 
  public void addUser() { 
    System.out.println(" increase 1 User... "); 
  } 
 
  public void editUser() { 
    System.out.println(" The editor 1 User... "); 
  } 
 
} 

3. Proxy class

/**
* the proxy class
*
* @author pc
*
*/
public class UserServiceProxy implements UserService {

private UserServiceImpl userImpl;

public UserServiceProxy(UserServiceImpl countImpl) {
this.userImpl = countImpl;
}

public void addUser() {
System.out.println (" proxy class method, enhanced... ") );
System.out.println(" transaction begins... ") );
// calls the methods of the delegate class;
userImpl.addUser();
System.out.println(" end of processing... ") );
}

public void editUser() {
System.out.println (" proxy class method, enhanced... ") );
System.out.println (" transaction begins... ") );
// calls the methods of the delegate class;
userImpl.editUser();
System.out.println (" transaction ends... ") );
}

}

4. Test


public static void main(String[] args) { 
  UserServiceImpl userImpl = new UserServiceImpl(); 
  UserServiceProxy proxy = new UserServiceProxy(userImpl); 
  proxy.addUser(); 
  System.out.println("---------- The divider ----------"); 
  proxy.editUser(); 
} 

5, the results

Proxy class methods, enhanced...

Transaction begins...
Add 1 user...
End of processing...

-- dividing line --

Proxy class methods, enhanced...
Transaction begins...
Edit 1 user...
Transaction ends...

3. jdk dynamic proxy

1. Business interface


/** 
 *  Business interface  
 * @author pc 
 * 
 */
public interface UserService { 
   
  //  increase 1 A user  
  public void addUser(); 
  //  Edit account  
  public void editUser(); 
 
} 

2. Business interface implementation class


/** 
 *  Business interface implementation class  
 * @author pc 
 * 
 */
public class UserServiceImpl implements UserService { 
 
  public void addUser() { 
    System.out.println(" increase 1 User... "); 
  } 
 
  public void editUser() { 
    System.out.println(" The editor 1 User... "); 
  } 
} 

3. Proxy class


import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
 
/** 
 * 
 * @author pc 
 * 
 */
public class ServiceInvocationHandler implements InvocationHandler { 
 
  //  The target object  
  private Object target; 
 
  public ServiceInvocationHandler(Object target) { 
    super(); 
    this.target = target; 
  } 
 
  /** 
   *  Create a proxy instance  
   * @return 
   * @throws Throwable 
   */
  public Object getProxy() throws Throwable { 
    return Proxy.newProxyInstance(Thread.currentThread() 
        .getContextClassLoader(), this.target.getClass() 
        .getInterfaces(), this); 
    //  Writing this way only returns the target object, not the proxy object.  
    // return target; 
  } 
 
  /** 
   *  implementation InvocationHandler Interface methods  
   *  Execute the methods of the target object and enhance them  
   */
  public Object invoke(Object proxy, Method method, Object[] args) 
      throws Throwable { 
    Object result = null; 
    System.out.println(" Proxy class methods, enhanced... "); 
    System.out.println(" Transaction begins... "); 
    //  Execute the target method object  
    result = method.invoke(target, args); 
    System.out.println(" Transaction ends... "); 
    return result; 
  } 
 
} 

4. Test


public class Test { 
  /** 
   * jdk The dynamic proxy is generated 1 Three dynamic proxy classes, generate the corresponding bytecode, and then pass ClassLoader Load the bytecode.  
   *  The instance inherits Proxy Class, which implements the business interface, is called by reflection in the implemented methods InvocationHandler Interface implementation class  
   *  the invoke() Callback method.  
   * @param args 
   * @throws Throwable 
   */
  public static void main(String[] args) throws Throwable { 
    UserService userService = new UserServiceImpl(); 
    ServiceInvocationHandler handler = new ServiceInvocationHandler(userService); 
    //  Generate the proxy object based on the target  
    UserService proxy = (UserService) handler.getProxy(); 
    proxy.addUser(); 
//   proxy.editUser(); 
 
  } 
 
} 

5. Test results

Proxy class methods, enhanced...
Transaction begins...
Add 1 user...
Transaction ends...

4. cglib dynamic proxy

The jar package of cglib needs to be introduced.

Add dependencies in pom.xml:


<!-- https://mvnrepository.com/artifact/cglib/cglib --> 
<dependency> 
  <groupId>cglib</groupId> 
  <artifactId>cglib</artifactId> 
  <version>2.2.2</version> 
</dependency> 

1. Business class, no interface is implemented


/** 
 *  Business class  
 *  No implemented interface  
 *  If a class is final , the proxy object cannot be generated and an error is reported.  
 *  If the method is final The agent is invalid  
 * @author pc 
 * 
 */
public class UserServiceImpl { 
 
  public void addUser() { 
    System.out.println(" increase 1 User... "); 
  } 
 
  public void editUser() { 
    System.out.println(" The editor 1 User... "); 
  } 
} 

2. Proxy class


import java.lang.reflect.Method; 
 
import net.sf.cglib.proxy.Enhancer; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 
 
/** 
 *  use Cglib A dynamic proxy  
 * @author pc 
 * 
 */
public class UserServiceCglib implements MethodInterceptor{ 
 
  private Object target; 
   
  /** 
   *  Create a proxy instance  
   * @param target 
   * @return 
   */
  public Object getInstance(Object target){ 
    this.target = target; 
    Enhancer enhancer = new Enhancer(); 
    enhancer.setSuperclass(this.target.getClass()); 
    //  Set the callback method  
    enhancer.setCallback(this); 
    //  Create a proxy object  
    return enhancer.create(); 
  } 
   
  /** 
   *  implementation MethodInterceptor The method to override the interface.  
   *  The callback method  
   */
  public Object intercept(Object obj, Method method, Object[] args, 
      MethodProxy proxy) throws Throwable { 
    System.out.println(" Transaction begins... ");   
    Object result = proxy.invokeSuper(obj, args);   
    System.out.println(" Transaction ends... ");   
    return result;   
  } 
 
} 

3. Test


/** 
 *  Business implementation class  
 * @author pc 
 * 
 */
public class UserServiceImpl implements UserService { 
 
  public void addUser() { 
    System.out.println(" increase 1 User... "); 
  } 
 
  public void editUser() { 
    System.out.println(" The editor 1 User... "); 
  } 
 
} 
0

4. Results:

Transaction begins...
Add 1 user...
Transaction ends...

5. If the business implementation class is defined as final, the following error is reported


/** 
 *  Business implementation class  
 * @author pc 
 * 
 */
public class UserServiceImpl implements UserService { 
 
  public void addUser() { 
    System.out.println(" increase 1 User... "); 
  } 
 
  public void editUser() { 
    System.out.println(" The editor 1 User... "); 
  } 
 
} 
1

5. To summarize

1, the principle of

jdk static proxy implementation is relatively simple, 1 is the direct proxy object directly wrapped the proxied object.

jdk dynamic proxy is an interface proxy. The proxied class A needs to implement the business interface, and the business agent class B needs to implement the InvocationHandler interface.

The jdk dynamic proxy will generate an jdk proxy class that inherits the Proxy class according to the proxied object and implements the business interface. The bytecode of this class will be loaded by the ClassLoader passed in to create the jdk proxy object instance.

When the jdk proxy object instance is created, the business proxy object instance is assigned to the Proxy class, the jdk proxy object instance has the business proxy object instance, and the jdk proxy object instance creates the corresponding Method object m (possibly more than one) based on the business method of the proxy class through reflection. When an jdk proxy object instance calls a business method, such as proxy.addUser (); This will first pass the corresponding m object as a parameter to the invoke() method (the second parameter of the invoke method), invoke the jdk proxy object instance's invoke() callback method, and then invoke the proxy object through reflection inside the invoke method because the method, result = method.invoke (target, args); .

The cglib dynamic proxy is an inheritance proxy that modifies the bytecode through the ASM bytecode framework to generate new subclasses, override and enhance the functionality of the method.

2. Advantages and disadvantages

The jdk static proxy class can only serve one of the proxied classes, and if you need more proxy analogies, you will have too many proxy classes. jdk static proxy generates class files at compile time. It can be used directly and efficiently without being generated at run time.

jdk dynamic agents must implement interfaces, dynamically proxy methods through reflection, and consume system performance. However, there is no need to generate too many proxy classes, avoiding the generation of duplicate code, and the system is more flexible.

The cglib dynamic proxy does not need to implement the interface, but does so by subclassing bytecode, one point faster than reflection, and has no performance issues. However, since cglib will inherit the proxied class and need to override the proxied method, the proxied class cannot be final and the proxied method cannot be final.

Therefore, cglib is more widely used.


Related articles: