English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Vertiefte Verständnis des Mechanismus der dynamischen Proxy in Java

Retrofit ist ein sehr gut entkoppelter Framework für Netzwerk-Anfragen, und während meiner neuesten Forschung habe ich eine sehr mächtige und praktische Technologie namens dynamischer Proxy entdeckt. Dieser Artikel dient als Vorwissen für Retrofit und wird Ihnen helfen zu verstehen: Welche Anwendungsszenarien gibt es für dynamische Proxies, was ist ein dynamischer Proxy, wie verwendet man ihn und wo liegen seine Einschränkungen?

Anwendungsszenarien des dynamischen Proxies

1. AOP - Aspect-Oriented Programming, Decoupling des Programms

Kurz gesagt, wenn Sie vorhaben, vor und nach dem Ausführen einiger Methoden in einigen Klassen gemeinsame Operationen durchzuführen, während im Methodenkörper individuelle Operationen ausgeführt werden--Verwenden Sie den dynamischen Proxy. Bei großen Geschäftsvolumina kann dies den Code reduzieren und die Wartbarkeit verbessern.

2. Möchten Sie bestimmte Methoden einer Drittanbieterbibliothek anpassen

Ich habe eine Drittanbieterbibliothek zitiert, aber einige ihrer Methoden erfüllen nicht meine Anforderungen, ich möchte einige dieser Methoden selbst neu schreiben oder einige spezielle Operationen vor und nach den Methoden hinzufügen--Verwenden Sie den dynamischen Proxy. Aber beachten Sie, dass diese Methoden begrenzt sind, ich werde es später erklären.

Was ist ein dynamischer Proxy

Das Diagramm ist zu abstrakt, lassen Sie uns mit einem Beispiel aus dem Leben beginnen.

Angenommen, Sie sind ein großer Vermieter (der Vertretene), Sie haben viele Häuser zu vermieten und denken, es ist zu mühsam, Mieter zu finden und möchten nicht selbst aktiv werden, daher suchen Sie jemanden, der Ihnen hilft (der Vertreter), diese Dinge zu verwalten, und dieser (Vertreter, also der Makler) erhebt Ihnen einige entsprechende Maklergebühren (zusätzliche Operationen beim Vermieten von Häusern). Für den Mieter ist der Makler der Vermieter und hilft Ihnen, einige Dinge zu erledigen.

Insgesamt ist das ein Beispiel für einen Proxy, und warum wird er "dynamischer Proxy" genannt? Wo zeigen sich die beiden Wörter "dynamisch"?

Wir können so denken, wenn Sie jedes Ihrer Häuser einen Vertreter einstellen, um Ihnen zu helfen, und Sie möchten ein weiteres Haus vermieten, müssen Sie wieder einen Vertreter einstellen, dann werden Sie viele Vertreter einstellen und hohe Maklerkosten verursachen, das kann als "statischer Proxy" bezeichnet werden.

Aber wenn wir alle Häuser einem Makler überlassen und ihn auffordern, zwischen mehreren Häusern dynamisch die Rolle zu wechseln, Ihnen zu helfen, jeden Mieter zu bewältigen, ist das ein "dynamischer Proxy"-Prozess. Eine der großen Merkmale des dynamischen Proxies ist, dass es keine Proxy-Klasse gibt, die während der Kompilierung ausgeführt wird, sondern erst zur Laufzeit generiert wird.

Lassen Sie uns ein Beispielcode betrachten

Operationen zur Vermietung des Hauses

/**
*Definieren Sie ein Interface
**/
public interface RentHouse {
void rent();//Haus vermieten
void charge(String str);//Kosten für die Vermietung erheben
}

Eigentümer

public class HouseOwner implements RentHouse {
public void rent() {
  System.out.println("I want to rent my house");
}
public void charge(String str) {
  System.out.println("You get : ") + str + "RMB HouseCharge.");
}
}

Makler

public class DynamicProxy implements InvocationHandler {
// Dies ist die reale Instanz, die wir vertreten möchten, d.h. der Eigentümer
private Object subject;
// Konstruktor, initialisiere den Wert der realen Instanz, die wir vertreten möchten
public DynamicProxy(Object subject) {
  this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  //  Bevor wir den echten Objektproxy erstellen, können wir einige unserer eigenen Operationen hinzufügen, und die Vermittlungsgebühr wird erhoben
  System.out.println("before "+method.getName()+" house");
  System.out.println("Methode:") + method.getName());
  //    Wenn die Methode "charge" ist, wird die Vermittlungsgebühr erhoben100 Yuan Vermittlungsgebühr.
  if (method.getName().equals("charge")) {
    method.invoke(subject, args);
    System.out.println("I will get 100 RMB ProxyCharge.");
  } else {
    //  Wenn der Proxy-Objekt die Methode des echten Objekts aufruft, springt es automatisch zum invoke-Methode des mit dem Proxy-Objekt verbundenen Handler-Objekts, um aufgerufen zu werden
    method.invoke(subject, args);
  }
  //  Nachdem wir den echten Objektproxy erstellt haben, können wir auch einige unserer eigenen Operationen hinzufügen
  System.out.println("after "+method.getName()+" house");
  return null;
}
}

Gast

public class Client {
public static void main(String[] args)
{
  //  Wir vertreten die reale Instanz--Eigentümer
  HouseOwner houseOwner = new HouseOwner();
  //  Wir ersetzen, welche reale Instanz wir vertreten möchten, übergeben wir diese Instanz, und letztlich wird über diese reale Instanz die Methode aufgerufen
  InvocationHandler handler = new DynamicProxy(houseOwner);
  /*
   * Durch das newProxyInstance-Verfahren von Proxy erstellen wir unseren Proxy-Objekt, lassen Sie uns die drei Parameter betrachten
   * der erste Parameter handler.getClass().getClassLoader(), hier verwenden wir das ClassLoader-Objekt dieser Klasse, um unseren Proxy-Objekt zu laden
   * der zweite Parameter realSubject.getClass().getInterfaces(), hier bieten wir dem Proxy-Objekt die von dem realen Objekt ausgeführten Schnittstellen an, was bedeutet, dass ich diesen realen Objekt vertrete, so dass ich die Methoden dieses Sets aufrufen kann
   * der dritte Parameter handler, hier haben wir diesen Proxy-Objekt mit dem obigen InvocationHandler-Objekt verknüpft
   */
  RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
      .getClass().getInterfaces(), handler);//eine dynamische Proxyklasse, Vermittler
  System.out.println(rentHouse.getClass().getName());
  rentHouse.rent();
  rentHouse.charge("10000");
}
}

Lassen Sie uns die Ausgabe betrachten

com.sun.proxy.$Proxy0
before rent house
Methode: rent
Ich möchte mein Haus mieten
after rent house
before charge house
Methode: charge
Sie erhalten: 10000 RMB HouseCharge.
I will get 100 RMB ProxyCharge.
after charge house
Vorgang beendet mit Ausgabecode 0

In der Ausgabe finden sich before rent house sowie after rent house, was bedeutet, dass wir Operationen vor und nach der Methode hinzufügen können. Sehen wir uns auch die Ausgabe I will get an. 100 RMB ProxyCharge. Der Vermittler hat10Keine Vermittlungsgebühren von 0 RMB, das bedeutet, dass wir nicht nur Operationen hinzufügen können, sondern auch diese Methode ersetzen oder direkt deren Ausführung verhindern können.

Am Anfang des Quellcodes zu lesen, können Sie viele Fragen haben, wir schauen uns im Folgenden an, wie man dynamische Proxies verwenden sollte.

Wie verwendet man dynamische Proxy?

Im Java-Dynamischen Proxy-Mechanismus gibt es zwei wichtige Klassen und Interfaces, nämlich InvocationHandler (Interface) und Proxy (Class), die für die Implementierung unseres dynamischen Proxies erforderlich sind.

Jede dynamische Proxy-Klasse muss den InvocationHandler-Interface (Code-Mediator) implementieren und jeder Proxy-Instanz ist ein Handler zugeordnet. Wenn wir eine Methode über den Proxy-Objekt aufrufen, wird der Aufruf durch den Methodenaufruf von InvocationHandler invoke (hier wird die Methodensteigerung geschrieben) weitergeleitet.

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

Wir sehen, dass dieser Method drei Parameter annimmt. Was bedeuten diese drei Parameter?

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//proxy: bezieht sich auf das wahre Objekt, das wir vertreten
//method: bezieht sich auf das Method-Objekt, das die Methode darstellt, die wir im echten Objekt aufrufen möchten
//args: bezieht sich auf die Parameter, die beim Aufruf einer Methode eines echten Objekts übergeben werden

Nun schauen wir uns die Klasse Proxy an

public static Object newProxyInstance(ClassLoader loader, Class<63;>[] interfaces, InvocationHandler h) throws IllegalArgumentException

Die Klasse Proxy dient dazu, dynamische Proxy-Objekte zu erstellen und bietet viele Methoden, aber die häufigste ist newProxyInstance:

public static Object newProxyInstance(ClassLoader loader, Class<63;>[] interfaces, InvocationHandler h) throws IllegalArgumentException

Die Funktion dieses Methods besteht darin, ein dynamisches Proxy-Objekt zu erhalten, das drei Parameter annimmt. Lassen Sie uns die Bedeutung dieser drei Parameter untersuchen

public static Object newProxyInstance(ClassLoader loader, Class<63;>[] interfaces, InvocationHandler h) throws IllegalArgumentException
//loader: ein ClassLoader-Objekt, das definiert, durch welchen ClassLoader-Objekt die generierten Proxy-Objekte geladen werden
//interfaces: eine Array von Interface-Objekten, das darstellt, welche Schnittstellen ich den zu vertretenden Objekten bereitstellen werde. Wenn ich eine Gruppe von Schnittstellen bereitstelle, beansprucht der Proxy-Objekt, dass er diese Schnittstelle implementiert (Polymorphie), so dass ich die Methoden dieser Schnittstellen aufrufen kann
//h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法时,会关联到哪一个InvocationHandler对象上

这样一来,结合上面给出的代码,我们就可以明白动态代理的使用方法了

动态代理的局限性

从动态代理的使用方法中我们看到其实可以被增强的方法都是实现了接口的(不实现接口的public方法也可以通过继承被代理类来使用),代码中的HouseOwner继承了RentHouse。而对于private方法,JDK的动态代理无能为力!
以上的动态代理是JDK的,对于Java工程还有大名鼎鼎的CGLib,但遗憾的是CGLib并不能在Android中使用,Android虚拟机相对于JVM还是有区别的。

结束语

动态代理的应用场景远不止这些,内部原理将在以后的文章中介绍,但应用类反射临时生成代理类这一机制决定它对性能会有一定的影响。本文作为retrofit原理的前置文章并没有太过详尽,如有疏漏和错误,欢迎指正!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

声明:本文内容来自网络,版权归原作者所有。内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:notice#oldtoolbag.com(在发邮件时,请将#更换为@进行举报,并提供相关证据。一经查实,本站将立即删除涉嫌侵权内容。)

Vermutlich gefällt Ihnen