Home  >  Article  >  Java  >  Detailed explanation and example code of proxy pattern in Java

Detailed explanation and example code of proxy pattern in Java

高洛峰
高洛峰Original
2017-02-07 13:08:031434browse

java Detailed explanation of proxy mode

Preface:

In some cases, a client does not want or cannot directly reference an object. In this case, it can use a third party called a "proxy" Three to achieve indirect reference. The proxy object can play an intermediary role 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 needs through the proxy object.

Simply put, the proxy mode is to access an actual object through a proxy object, and can add some functions to the object like the decoration mode.

Static Agent

The so-called static agent means that the agent class already exists before the program is run. That is to say, when we write the code, we have already written the code of the agent class, and the dynamic agent The proxy class is automatically generated when the program is running.

The description is too abstract. Just look at the code and you will understand what is going on

main

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

##Interface

//代理类与被代理类共同实现的接口
public interface Drink {
  void drink();
}

Proxy class

//被代理的类
public class Water implements Drink {
 
  @Override
  public void drink() {
    System.out.println("drink water");
  }
 
}

Agent class

//代理类
//与被代理类实现同一个接口
public class DrinkProxy implements Drink {
   
  private Drink drinkImpl;
   
  //通过构造函数传入Water对象
  public DrinkProxy(Drink drinkImpl) {
    this.drinkImpl = drinkImpl;
  }
   
  @Override
  public void drink() {
    //在执行被代理对象的方法前做一些事情
    System.out.println("before drink");
    //执行被代理对象的方法
    drinkImpl.drink();
    //在执行被代理对象的方法后做一些事
    System.out.println("after drink");
  }
 
}

Execution results

before drink
drink water
after drink

Dynamic proxy

Sometimes we just want to change the proxy class represented by Class, but the proxy object does the same thing before and after executing the method of the actual object. It is the so-called iron-clad proxy class and the streamlined proxy class. With static proxy, you can only proxy classes that implement the same interface. If you want to proxy any class, you must write many duplicate proxy classes. At this time, we can use dynamic proxy. Java has provided a set of convenient tools for implementing dynamic proxy.

Methods in the java.lang.reflect.Proxy class that can dynamically generate proxy objects

/**
   *返回实现了指定接口的对象,调用代理对象的方法会调用
   *InvocationHandler的invoke方法
   *
   * @param  loader 获取代理类所使用的类加载器
   * @param  interfaces 代理类所要实现的接口
   * @param  h 实现了InvocationHandler接口的对象
   * @return 代理对象
   */
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)

InvocationHandler interface

/**
 *每个代理类都有一个关联的InvocationHandler
 *当代理对象执行一个方法的时候会直接执行invoke方法
 */
public interface InvocationHandler {
 
  /**
   * @param  调用该方法的代理对象
   * @param  method 代理对象所调用的方法
   * @param  args 调用的方法的参数
   * @return 调用的方法的返回值
   */
  public Object invoke(Object proxy, Method method, Object[] args)
}

The description is always abstract, it is easier to understand by looking at actual examples

Example

InvocationHandler interface implementation class

public class CommonInvocationHandler implements InvocationHandler {
   
  //被代理的对象
  private Object proxied;
   
  public CommonInvocationHandler(Object proxied) {
    this.proxied = proxied;
  }
   
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //在调用被代理对象的方法前做一些事情
    System.out.println("before doing something");
    //调用被代理对象的方法
    Object result = method.invoke(proxied, args);
    //在调用被代理对象的方法后做一些事情
    System.out.println("after doing something");;
    return result;
  }
 
}

Main

public class Main {
 
  public static void main(String[] args) {
    //被代理的对象
    Water water = new Water();
    //动态获取代理对象
    Drink waterProxy =
        (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(),
            water.getClass().getInterfaces(),
            new CommonInvocationHandler(water));
    //通过代理对象调用方法
    waterProxy.drink();
  }
 
}

Output result

before doing something
drink water
after doing something

You don’t need a specific proxy object, but you must have a corresponding interface (classes that do not implement the interface can use cglib to implement dynamic proxy) before you can dynamically obtain the proxy object. For example, the recently popular Retrofit uses a dynamic proxy to make network requests directly through the declared interface.

Example

Simple simulation of retrofit

POST annotation

//Post请求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}

Query annotation

//Post请求注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface POST {
 String value() default "";
}

##Service interface

public interface Service {
  //用POST注解声明请求的方式和相对路径
  @POST("/login")
  //@Query注解声明请求的参数名
  void login(@Query("username")String username,
      @Query("password")String password);
}

##Main

public class Main {
 
  public static void main(String[] args) {
    // 动态获取Service接口的代理
    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 {
            // 通过注解获取请求的相对路径
            String retativePath = ((POST) method.getAnnotations()[0]).value();
            System.out.println("relative path: " + retativePath);
            // 获取参数的注解
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            // 通过参数的注解获取请求参数
            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;
          }
        });
    // 调用代理对象的方法
    service.login("hello", "world");
  }
 
}

Thank you for reading, I hope it can help you, thank you for your support of this site!

For more detailed explanations and example code related articles about the proxy mode in Java, please pay attention to the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn