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

Capire a fondo il meccanismo di proxy dinamico in Java

Retrofit è un framework di richiesta di rete con un alto grado di decoupling, recentemente ho scoperto questa tecnologia molto potente e pratica chiamata proxy dinamico mentre stavo studiando. Questo articolo sarà un'informazione preliminare su retrofit, in modo che possiate conoscere: quali sono le applicazioni del proxy dinamico, cos'è il proxy dinamico, come utilizzarlo e dove si trovano le sue limitazioni?

Applicazioni del proxy dinamico

1. AOP - programmazione orientata agli aspect, decoupling del programma

In breve, quando si desidera eseguire alcune operazioni comuni prima e dopo i metodi interni di alcune classi, e quando si desidera eseguire operazioni personalizzate nei metodi stessi - utilizzare il proxy dinamico. In presenza di un grande volume di lavoro, è possibile ridurre la quantità di codice e migliorare la manutenibilità.

2. Voglio personalizzare alcuni metodi di una libreria di terze parti

Ho citato una libreria di terze parti, ma alcuni dei suoi metodi non soddisfano le mie esigenze. Voglio riscrivere quei metodi da solo o aggiungere alcune operazioni speciali prima e dopo i metodi - utilizzando il proxy dinamico. Tuttavia, è necessario notare che questi metodi hanno limitazioni, lo spiegherò più tardi.

什么是动态代理

以上的图太过于抽象,我们从生活中的例子开始切入。

假如你是一个大房东(被代理人),你有很多套房子想要出租,而你觉得找租客太麻烦,不愿意自己弄,因而你找一个人来代理你(代理人),帮打理这些东西,而这个人(代理人也就是中介)在帮你出租房屋的时候对你收取一些相应的中介费(对房屋出租的一些额外操作)。对于租客而言,中介就是房东,代理你做一些事情。

以上,就是一个代理的例子,而他为什么叫动态代理,“动态”两个字体现在什么地方?

我们可以这样想,如果你的每一套房子你都请一个代理人帮你打理,每当你想再出租一套房子的时候你得再请一个,这样你会请很多的代理人,花费高额的中介成本,这可以看作常说的“静态代理”。

但假如我们把所有的房子都交给一个中介来代理,让他在多套房子之间动态的切换身份,帮你应付每一个租客。这就是一个“动态代理”的过程。动态代理的一大特点就是编译阶段没有代理类在运行时才生成代理类。

我们用一段代码来看一下

房屋出租的操作

/**
*定义一个接口
**/
public interface RentHouse {
void rent();//房屋出租
void charge(String str);//出租费用收取
}

proprietario

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

agenzia immobiliare

public class DynamicProxy implements InvocationHandler {
// 这个就是我们要代理的真实对象,即房东
private Object subject;
// 构造方法,给我们要代理的真实对象赋初值
public DynamicProxy(Object subject) {
  this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  //  Possiamo aggiungere alcune operazioni proprie prima dell'agente reale, l'agente riceve la Commissione
  System.out.println("before " + method.getName() + " house");
  System.out.println("Method:" + method.getName());
  //    Se il metodo è charge, l'agente riceve 100 yuan di Commissione
  if (method.getName().equals("charge")) {
    method.invoke(subject, args);
    System.out.println("Otterrò 100 RMB di Commissione.");
  } else {
    //  Quando l'oggetto proxy chiama il metodo dell'oggetto reale, viene automaticamente reindirizzato al metodo invoke dell'oggetto handler associato per la chiamata
    method.invoke(subject, args);
  }
  //  Possiamo aggiungere alcune operazioni proprie dopo l'agente reale
  System.out.println("after " + method.getName() + " house");
  return null;
}
}

ospite

public class Client {
public static void main(String[] args)
{
  //  L'oggetto reale che vogliamo代理 è l'inquilino
  HouseOwner houseOwner = new HouseOwner();
  //  Passiamo l'oggetto reale che vogliamo代理 a questa funzione, e infine chiamiamo i suoi metodi tramite questo oggetto reale
  InvocationHandler handler = new DynamicProxy(houseOwner);
  /*
   * Creiamo il nostro oggetto proxy utilizzando il metodo newProxyInstance di Proxy e vediamo i suoi tre parametri
   * Il primo parametro handler.getClass().getClassLoader() utilizza l'oggetto ClassLoader della classe handler per caricare il nostro oggetto proxy
   * Il secondo parametro realSubject.getClass().getInterfaces(), in questo caso forniamo all'oggetto proxy l'interfaccia eseguita dall'oggetto reale, il che significa che sto代理 il questo oggetto reale, così posso chiamare i metodi di questo set di interfacce
   * Il terzo parametro handler, in questo caso associamo l'oggetto proxy all'oggetto InvocationHandler in alto
   */
  RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
      .getClass().getInterfaces(), handler);//Una classe di proxy dinamico, agente
  System.out.println(rentHouse.getClass().getName());
  rentHouse.rent();
  rentHouse.charge("10000");
}
}

Guardiamo l'uscita

com.sun.proxy.$Proxy0
before rent house
Method:rent
Voglio affittare la mia casa
after rent house
before charge house
Method:charge
Ti spetta: 10000 RMB HouseCharge.
I will get 100 RMB ProxyCharge.
after charge house
Processo finito con codice di uscita 0

Nella uscita ci sono before rent house e after rent house, il che significa che possiamo aggiungere operazioni prima e dopo il metodo. Guarda anche l'uscita I will get 100 RMB ProxyCharge. La agenzia ha收取 100 yuan di tassa di agenzia, il che significa che non solo possiamo aggiungere operazioni, ma possiamo anche sostituire il metodo o farlo eseguire direttamente.

All'inizio, guardando il codice, potresti avere molte domande, esaminiamo i seguenti contenuti per vedere come utilizzare il proxy dinamico.

Come utilizzare il proxy dinamico

Nel meccanismo di代理 dinamico di Java, ci sono due classi e interfacce importanti, una è InvocationHandler (Interface), l'altra è Proxy (Class), queste due classi e interfacce sono necessarie per implementare il nostro代理 dinamico.

Ogni classe proxy dinamica deve implementare l'interfaccia InvocationHandler (mediatore nel codice), e ogni istanza di classe proxy è associata a un handler, quando chiamiamo un metodo tramite l'oggetto proxy, la chiamata del metodo viene inoltrata al metodo invoke dell'interfaccia InvocationHandler (l'incremento di funzionalità del metodo si scrive qui).

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

Vediamo che questo metodo accetta tre parametri, allora cosa rappresentano questi tre parametri?

Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//proxy: indica l'oggetto reale che stiamo代理
//method: indica l'oggetto Method che rappresenta il metodo che vogliamo chiamare dell'oggetto reale
//args: indica i parametri accettati quando si chiama un metodo di un oggetto reale

Prossimamente, diamo un'occhiata alla classe Proxy

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

La classe Proxy serve per creare dinamicamente un oggetto proxy, fornisce molti metodi, ma quelli che usiamo di più sono newProxyInstance:

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

Il ruolo di questo metodo è ottenere un oggetto proxy dinamico, che accetta tre parametri, diamo un'occhiata al significato di questi tre parametri

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
//loader: un oggetto ClassLoader, che definisce quale oggetto ClassLoader caricherà l'oggetto proxy generato
//interfaces: un array di oggetti Interface, che rappresenta le interfacce che fornirò agli oggetti che devo代理, se fornisco un insieme di interfacce, l'oggetto proxy dichiarerà di implementare l'interfaccia (polimorfismo), così potrò chiamare i metodi di questo insieme di interfacce
//h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上

//h: un oggetto InvocationHandler, che rappresenta il fatto che quando questo oggetto proxy dinamico chiama un metodo, verrà associato a quale oggetto InvocationHandler

In questo modo, combinando il codice fornito sopra, possiamo capire come utilizzare il proxy dinamico

Limitazioni del proxy dinamico
Dalla guida all'uso del proxy dinamico vediamo che possono essere migliorati i metodi sono implementati tramite proxy (i metodi public non implementati tramite proxy possono essere utilizzati attraverso l'ereditarietà della classe proxy), nel codice HouseOwner eredita RentHouse. Per i metodi private, il proxy dinamico di JDK non può fare nulla!

Conclusione

Le scenari di utilizzo dell'proxy dinamico vanno oltre questi, i principi interni saranno illustrati in articoli futuri, ma il meccanismo di generazione temporanea di classi代理 attraverso la reflection di classe applicativa determina che avrà un impatto sul prestazioni. Questo articolo come articolo preparatorio per il principio di retrofit non è troppo dettagliato, benvenuti a correggere errori e omissioni!

Questo è tutto il contenuto dell'articolo, spero che sia utile per la tua apprendimento e che tu sostenga fortemente la guida a urla.

Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, il copyright è dell'autore originale, il contenuto è stato contribuito autonomamente dagli utenti di Internet e caricato autonomamente, il sito web non detiene i diritti di proprietà, non è stato editato manualmente e non assume responsabilità legali correlate. Se trovi contenuti sospetti di violazione del copyright, sei invitato a inviare una e-mail a notice#oldtoolbag.com (sostituisci # con @ quando invii l'e-mail) per segnalare il problema e fornire prove pertinenti. Una volta verificata, il sito web eliminerà immediatamente i contenuti sospetti di violazione del copyright.

Ti potrebbe interessare