Maison >Java >javaDidacticiel >Explication détaillée et exemple de code du modèle de proxy en Java

Explication détaillée et exemple de code du modèle de proxy en Java

高洛峰
高洛峰original
2017-02-07 13:08:031454parcourir

Explication détaillée du mode proxy java

Avant-propos :

Dans certains cas, un client ne veut pas ou ne peut pas référencer directement un objet. Dans ce cas, il peut passer un troisième objet appelé. un "proxy" Trois pour obtenir une référence indirecte. L'objet proxy peut agir comme intermédiaire entre le client et l'objet cible, et peut supprimer le contenu et les services que le client ne peut pas voir ou ajouter des services supplémentaires dont le client a besoin via l'objet proxy.

En termes simples, le mode proxy consiste à accéder à un objet réel via un objet proxy et peut ajouter certaines fonctions à l'objet comme le mode décoration.

Procuration statique

Le proxy dit statique signifie que la classe proxy existe déjà avant l'exécution du programme, c'est-à-dire que lorsque nous écrivons le code, nous avons déjà écrit le code. de la classe proxy et du proxy dynamique La classe proxy est automatiquement générée lors de l'exécution du programme.

La description est trop abstraite. Il suffit de regarder le code et vous comprendrez ce qui se passe

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();
}

Classe proxy

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

Classe proxy

//代理类
//与被代理类实现同一个接口
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");
  }
 
}

Résultat de l'exécution

before drink
drink water
after drink

Procuration dynamique

Parfois, nous voulons simplement changer la classe représentée par la classe proxy, mais l'objet proxy fait la même chose avant et après l'exécution de la méthode de l'objet réel. Comme le dit le proverbe, la classe proxy à toute épreuve est le proxy fluide. classe. Avec un proxy statique, vous ne pouvez proxy que des classes qui implémentent la même interface. Si vous souhaitez proxy n'importe quelle classe, vous devez écrire de nombreuses classes proxy en double. À l'heure actuelle, nous pouvons utiliser un proxy dynamique. Java a fourni un ensemble d'outils pratiques pour implémenter un proxy dynamique.

Méthodes de la classe java.lang.reflect.Proxy qui peuvent générer dynamiquement des objets proxy

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

Interface InvocationHandler

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

La description est toujours abstraite, elle est plus facile à comprendre en regardant des exemples réels

Exemple

Classe d'implémentation de l'interface InvocationHandler

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;
  }
 
}

Principal

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();
  }
 
}

Résultat de sortie

before doing something
drink water
after doing something

Vous n'avez pas besoin d'un objet proxy spécifique, mais il doit y avoir une interface correspondante (les classes qui n'implémentent pas l'interface peuvent utiliser cglib pour implémenter un proxy dynamique) avant vous pouvez obtenir dynamiquement l'objet proxy. Par exemple, Retrofit, récemment populaire, utilise un proxy dynamique pour effectuer des requêtes réseau directement via l'interface déclarée.

Exemple

Simulation simple de rénovation

Annotation POST

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

Annotation de requête

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

Interface de service

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

Principale

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");
  }
 
}

Merci d'avoir lu, j'espère que cela pourra aider tout le monde, merci pour votre soutien à ce site !

Pour des explications plus détaillées et des exemples d'articles sur le code sur le mode proxy en Java, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn