Agent pattern details and example code in Java

  • 2020-06-03 06:25:00
  • OfStack

Detailed explanation of java agent pattern

Preface:

In cases where a client does not want or cannot directly reference an object, an indirect reference can be achieved through a third party called a proxy. The proxy object can mediate between the client and the target object and can remove content and services that the client cannot see or add additional services that the client requires.

In simple terms, proxy mode is to access 1 real object through 1 proxy object and add 1 function to the object as in decorative mode 1.

Static agent

The so-called static proxy means that the proxy class already exists before the program runs, that is, the code of the proxy class is written when we write the code, while the dynamic proxy automatically generates the proxy class when the program runs.

It's too abstract to describe, but look at the code in 1 to see what's going on. Okay

main


public class Main {

  public static void main(String[] args) {
    Water water = new Water();
    WaterProxy waterProxy = new WaterProxy(water);
    waterProxy.drink();
  }

}

interface


// The interface that the broker class implements with the broker class 
public interface Drink {
  void drink();
}

By the proxy class


// The class being represented 
public class Water implements Drink {

  @Override
  public void drink() {
    System.out.println("drink water");
  }

}

The proxy class


// The proxy class 
// Same as the broker class implementation 1 An interface 
public class DrinkProxy implements Drink {
  
  private Drink drinkImpl;
  
  // Passed in through the constructor Water object 
  public DrinkProxy(Drink drinkImpl) {
    this.drinkImpl = drinkImpl;
  }
  
  @Override
  public void drink() {
    // Do this before executing the method of the object being represented 1 Some of the things 
    System.out.println("before drink");
    // Executes the methods of the proxy object 
    drinkImpl.drink();
    // After executing the method of the object being represented 1 something 
    System.out.println("after drink");
  }

}

The execution result


before drink
drink water
after drink

A dynamic proxy

Sometimes we just want to change the class that the proxy class is acting on, but the proxy object does exactly the same thing before and after it executes the methods of the actual object. Using static proxy can only proxy classes that implement the same interface as 1. If you want to proxy any class, you must write many duplicate proxy classes. At this point, we can use dynamic proxy. Java has provided a set of convenient tools for dynamic proxy implementation.

java. lang. reflect. Proxy can dynamically generated proxy objects in the class of methods


/**
   * Returns the object that implements the specified interface, and the method that calls the proxy object is called  
   *InvocationHandler the invoke methods 
   *
   * @param  loader  Gets the classloader used by the proxy class 
   * @param  interfaces  The interface that the proxy class is going to implement 
   * @param  h  To achieve the InvocationHandler Object of the interface 
   * @return  Proxy objects 
   */
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

InvocationHandler interface


/**
 * Each proxy class has one 1 An associated InvocationHandler
 * When the proxy object executes 1 Method will be executed directly invoke methods 
 */
public interface InvocationHandler {

  /**
   * @param   The proxy object that calls this method 
   * @param  method  The method invoked by the proxy object 
   * @param  args  The parameters of the called method 
   * @return  The return value of the called method 
   */
  public Object invoke(Object proxy, Method method, Object[] args)
}


The description is always abstract, but it's easier to understand by looking at the actual example

example

Implementation class for the InvocationHandler interface


public class CommonInvocationHandler implements InvocationHandler {
  
  // The object being represented 
  private Object proxied;
  
  public CommonInvocationHandler(Object proxied) {
    this.proxied = proxied;
  }
  
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // Do this before invoking the method of the object being represented 1 Some of the things 
    System.out.println("before doing something");
    // Invokes the method of the proxy object 
    Object result = method.invoke(proxied, args);
    // After invoking the method of the object being represented 1 Some of the things 
    System.out.println("after doing something");;
    return result;
  }

}

Main


public class Main {

  public static void main(String[] args) {
    // The object being represented 
    Water water = new Water();
    // Get the proxy object dynamically 
    Drink waterProxy = 
        (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(),
            water.getClass().getInterfaces(), 
            new CommonInvocationHandler(water));
    // Call a method through a proxy object 
    waterProxy.drink();
  }

}

The output


before doing something
drink water
after doing something

It is also possible not to have a concrete proxy object, but to get a proxy object dynamically, you must have an interface (classes that do not implement an interface can use cglib to implement dynamic proxies). A recent hit like Retrofit USES dynamic proxies to make network requests directly through a declared interface.

example

Simple simulation 1 under retrofit

POST annotations


// The interface that the broker class implements with the broker class 
public interface Drink {
  void drink();
}
0

Query annotations


// The interface that the broker class implements with the broker class 
public interface Drink {
  void drink();
}
1

Service interface


// The interface that the broker class implements with the broker class 
public interface Drink {
  void drink();
}
2

Main


public class Main {

  public static void main(String[] args) {
    //  Dynamic access Service Proxy for interfaces 
    Service service = (Service) Proxy.newProxyInstance(Service.class.getClassLoader(),
        new Class[] { Service.class }, new InvocationHandler() {

          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //  Gets the relative path of the request by annotation 
            String retativePath = ((POST) method.getAnnotations()[0]).value();
            System.out.println("relative path: " + retativePath);
            //  Gets a comment for the parameter 
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            //  Get the request parameters by annotating the parameters 
            for (int i = 0; i < parameterAnnotations.length; i++) {
              if (parameterAnnotations[i].length != 0) {
                for (int j = 0; j < parameterAnnotations[i].length; j++) {
                  Query query = (Query) parameterAnnotations[i][j];
                  System.out.println(query.value() + ": " + args[i].toString());
                }
              }
            }
            return null;
          }
        });
    //  Call the method of the proxy object 
    service.login("hello", "world");
  }

}

Thank you for reading, I hope to help you, thank you for your support to this site!


Related articles: