Heim  >  Artikel  >  Java  >  Ausführliche Erklärung und Beispielcode des Proxy-Musters in Java

Ausführliche Erklärung und Beispielcode des Proxy-Musters in Java

高洛峰
高洛峰Original
2017-02-07 13:08:031369Durchsuche

Detaillierte Erläuterung des Java-Proxy-Modus

Vorwort:

In manchen Fällen möchte oder kann ein Client nicht direkt auf ein Objekt verweisen. In diesem Fall kann er ein drittes aufgerufenes Objekt übergeben ein „Proxy“ Drei, um eine indirekte Referenz zu erreichen. Das Proxy-Objekt kann eine Vermittlerrolle zwischen dem Client und dem Zielobjekt spielen und über das Proxy-Objekt Inhalte und Dienste entfernen, die der Client nicht sehen kann, oder zusätzliche Dienste hinzufügen, die der Client benötigt.

Einfach ausgedrückt besteht der Proxy-Modus darin, über ein Proxy-Objekt auf ein tatsächliches Objekt zuzugreifen und dem Objekt einige Funktionen wie den Dekorationsmodus hinzuzufügen.

Statischer Proxy

Der sogenannte statische Proxy bedeutet, dass die Proxy-Klasse bereits existiert, bevor das Programm ausgeführt wird. Das heißt, wenn wir den Code schreiben, haben wir den Code bereits geschrieben der Proxy-Klasse und des dynamischen Proxys Die Proxy-Klasse wird automatisch generiert, wenn das Programm ausgeführt wird.

Die Beschreibung ist zu abstrakt. Schauen Sie sich einfach den Code an und Sie werden verstehen, was los ist.

main

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

Schnittstelle

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

Proxy-Klasse

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

Proxy-Klasse

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

Ausführungsergebnis

before drink
drink water
after drink

Dynamischer Proxy

Manchmal möchten wir nur die durch die Proxy-Klasse dargestellte Klasse ändern, aber das Proxy-Objekt macht vor und nach der Ausführung der Methode des eigentlichen Objekts dasselbe. Wie das Sprichwort sagt, ist die eiserne Proxy-Klasse der glatte Proxy Klasse. Mit einem statischen Proxy können Sie nur Klassen vertreten, die dieselbe Schnittstelle implementieren. Wenn Sie eine beliebige Klasse vertreten möchten, müssen Sie viele doppelte Proxy-Klassen schreiben. Derzeit können wir dynamische Proxys verwenden. Java bietet eine Reihe praktischer Tools zur Implementierung dynamischer Proxys.

Methoden in der Klasse java.lang.reflect.Proxy, die Proxy-Objekte dynamisch generieren können

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

InvocationHandler-Schnittstelle

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

Die Beschreibung ist immer abstrakt, sie ist leichter zu verstehen, wenn man sich tatsächliche Beispiele ansieht

Beispiel

InvocationHandler-Schnittstellenimplementierungsklasse

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

Haupt

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

Ausgabeergebnis

before doing something
drink water
after doing something

Sie benötigen kein bestimmtes Proxy-Objekt, es muss jedoch vorher eine entsprechende Schnittstelle vorhanden sein (Klassen, die die Schnittstelle nicht implementieren, können cglib verwenden, um einen dynamischen Proxy zu implementieren). Sie können das Proxy-Objekt dynamisch abrufen. Beispielsweise verwendet das kürzlich beliebte Retrofit einen dynamischen Proxy, um Netzwerkanfragen direkt über die deklarierte Schnittstelle zu stellen.

Beispiel

Einfache Nachrüstungssimulation

POST-Anmerkung

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

Abfrageanmerkung

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

Serviceschnittstelle

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

Haupt

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

Vielen Dank fürs Lesen, ich hoffe, es kann allen helfen, vielen Dank für Ihre Unterstützung dieser Seite!

Ausführlichere Erklärungen und Artikel zum Beispielcode zum Proxy-Modus in Java finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn