Dynamic Proxy Agent

Preface

Dynamic proxy is actually Java The. lang.reflect.Proxy class dynamically generates a class byte based on all the interfaces you specify, which inherits the Proxy class and implements all the interfaces you specify (the array of interfaces you pass in parameters); then loads class byte into the system using the classloader you specify, finally generates an object of this class, and initializes some values of the object, such as invocatio NHandler, the Method member corresponding to all interfaces. After initialization, the object is returned to the calling client. So the client gets a Proxy object that implements all your interfaces.

Case study

A Business Interface

public interface BusinessProcessor {
   public void processBusiness();
}


Two Business Implementation Classes

public class BusinessProcessorImpl implements BusinessProcessor {
 public void processBusiness() {
  System.out.println("processing business.....");
 }
}


Three Business Agent Classes

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class BusinessProcessorHandler implements InvocationHandler {

 private Object target = null;
 
 BusinessProcessorHandler(Object target){
      this.target = target;
 }
 
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable {
      System.out.println("You can do something here before process your business");
      Object result = method.invoke(target, args);
      System.out.println("You can do something here after process your business");
      return result;
 }

}


Four Client Application Classes
 

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;

public class Test {

 public static void main(String[] args) {
      BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
      BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
      BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(),bpimpl.getClass().getInterfaces(), handler);
      bp.processBusiness();
 }
}



Now let's look at the print results:

You can do something here before process your business
processing business.....
You can do something here after process your business

Through the results, we can easily see the role of Proxy, which can do some assistant work you want to do before and after your core business methods, such as log logs, security mechanisms and so on.

Now let's analyze how the above classes work. Class one or two is nothing to say. Let's look at category three first. The invoke method of Invocation Handler interface is implemented. In fact, this class is the fixed interface method that Proxy calls finally. Proxy does not matter how the client's business approach is implemented. When the client calls Proxy, it only calls InvocationHandler's invoke interface, so the method we really implement must be invoked in the invoke method. The relationship is as follows:

BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);
bp.processBusiness()-->invocationHandler.invoke()-->bpimpl.processBusiness();

So what kind of object is bp? Let's change the main method and see:

 

public static void main(String[] args) {
  .....
  System.out.println(bp.getClass().getName());
 }


Output results:

You can do something here before process your business
processing business.....
You can do something here after process your business
$Proxy0

bp was originally an object of the class $Proxy0. So what does this class look like? Well. Let's write two more ways to print out this class and see what it is, three heads and six arms? We write the following two static methods under main.

You don't even need to look at the following method, just know that it only prints class information.

public static String getModifier(int modifier){
  String result = "";
  switch(modifier){
   case Modifier.PRIVATE:
    result = "private";
    break;
   case Modifier.PUBLIC:
    result = "public";
    break;
   case Modifier.PROTECTED:
    result = "protected";
    break;
   case Modifier.ABSTRACT :
    result = "abstract";
    break;
   case Modifier.FINAL :
    result = "final";
    break;
   case Modifier.NATIVE :
    result = "native";
    break;
   case Modifier.STATIC :
    result = "static";
    break;
   case Modifier.SYNCHRONIZED :
    result = "synchronized";
    break;
   case Modifier.STRICT  :
    result = "strict";
    break;
   case Modifier.TRANSIENT :
    result = "transient";
    break;
   case Modifier.VOLATILE :
    result = "volatile";
    break;
   case Modifier.INTERFACE :
    result = "interface";
    break;
  }
  return result;
 }
 
 public static void printClassDefinition(Class clz){
  
  String clzModifier = getModifier(clz.getModifiers());
  if(clzModifier!=null && !clzModifier.equals("")){
   clzModifier = clzModifier + " ";
  }
  String superClz = clz.getSuperclass().getName();
  if(superClz!=null && !superClz.equals("")){
   superClz = "extends " + superClz;
  }
  
  Class[] interfaces = clz.getInterfaces();
  
  String inters = "";
  for(int i=0; i<interfaces.length; i++){
   if(i==0){
    inters += "implements ";
   }
   inters += interfaces[i].getName();
  }
  
  System.out.println(clzModifier +clz.getName()+" " + superClz +" " + inters );
  System.out.println("{");
  
  Field[] fields = clz.getDeclaredFields();
  for(int i=0; i<fields.length; i++){
   String modifier = getModifier(fields[i].getModifiers());
   if(modifier!=null && !modifier.equals("")){
    modifier = modifier + " ";
   }
   String fieldName = fields[i].getName();
   String fieldType = fields[i].getType().getName();
   System.out.println("    "+modifier + fieldType + " "+ fieldName + ";");
  }
  
  System.out.println();
  
  Method[] methods = clz.getDeclaredMethods();
  for(int i=0; i<methods.length; i++){
   Method method = methods[i];

   String modifier = getModifier(method.getModifiers());
   if(modifier!=null && !modifier.equals("")){
    modifier = modifier + " ";
   }
   
   String methodName = method.getName();
   
   Class returnClz = method.getReturnType();
   String retrunType = returnClz.getName();
   
   Class[] clzs = method.getParameterTypes();
   String paraList = "(";
   for(int j=0; j<clzs.length; j++){
    paraList += clzs[j].getName();
    if(j != clzs.length -1 ){
     paraList += ", ";
    }
   }
   paraList += ")";
   
   clzs = method.getExceptionTypes();
   String exceptions = "";
   for(int j=0; j<clzs.length; j++){
    if(j==0){
     exceptions += "throws ";
    }

    exceptions += clzs[j].getName();
    
    if(j != clzs.length -1 ){
     exceptions += ", ";
    }
   }
   
   exceptions += ";";
   
   String methodPrototype = modifier +retrunType+" "+methodName+paraList+exceptions;
   
   System.out.println("    "+methodPrototype );
   
  }
  System.out.println("}");
 }

     

Rewrite main method

public static void main(String[] args) {
  ......
  Class clz = bp.getClass();
  printClassDefinition(clz);
 }


Now let's look at the output:

You can do something here before process your business
processing business.....
You can do something here after process your business
$Proxy0
$Proxy0 extends java.lang.reflect.Proxy implements com.tom.proxy.dynamic.BusinessProcessor
{
    java.lang.reflect.Method m4;
    java.lang.reflect.Method m2;
    java.lang.reflect.Method m0;
    java.lang.reflect.Method m3;
    java.lang.reflect.Method m1;

    void processBusiness();
    int hashCode();
    boolean equals(java.lang.Object);
    java.lang.String toString();
}

summary

Obviously, the Proxy.newProxyInstance method does the following things:

1. A class is generated dynamically according to the second parameter, interfaces, to implement the interface in interfaces, in this case, the processBusiness method of Business Processor interface. And inherited the Proxy class, rewritten hashcode,toString,equals and other three methods. See ProxyGenerator.generateProxyClass(...) for specific implementation; in this case, $Proxy0 class is generated.

2. Load the newly generated class into the jvm by passing in the first parameter classloder. Up to $Proxy0 class load

3. Using the third parameter, invoke the $Proxy0 (Invocation Handler) constructor of $Proxy0 to create the object of $Proxy0, and use the interface parameter to traverse the method of all its interfaces, and generate several Method member variables of the method object initialization object.

4. Return an instance of $Proxy0 to the client.

It's alright now. Let's see how the client adjusts.

1. The client gets the instance object of $Proxy0. Since $Proxy0 inherits Business Processor, there is no problem in converting it into Business Processor.

BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);

2,bp.processBusiness();

Actually, $Proxy 0.processBusiness () is called; then the implementation of $Proxy 0.processBusiness () is to invoke the invoke method through Invocation Handler!

Keywords: Java jvm

Added by StormTheGates on Fri, 21 Jun 2019 04:21:16 +0300