— Bună, Amigo.

— Bună, Rishi.

„Astăzi vă voi explica un subiect nou și foarte interesant: proxy dinamici” .

„Java are mai multe moduri de a schimba funcționalitatea unei anumite clase…”

„Prima metodă este moștenirea”.

„Cea mai ușoară modalitate de a schimba comportamentul unei clase este de a crea o nouă clasă care moștenește clasa originală (de bază) și de a înlocui metodele acesteia. Apoi, în loc să utilizați clasa inițială, utilizați clasa derivată. De exemplu:”

Reader reader = new UserCustomReader();

„A doua metodă este să folosiți o clasă de înveliș”.

" BufferedReader este un exemplu de acest tip de clasă. În primul rând, moștenește Reader . Cu alte cuvinte, poate fi folosit în loc de Reader. În al doilea rând, redirecționează toate apelurile către obiectul Reader original , care trebuie să fie transmis constructorului obiectului BufferedReader. . De exemplu:"

Reader readerOriginal = new UserCustomReader();
Reader reader = new BufferedReader(readerOriginal);

„A treia metodă este de a crea un proxy dinamic (Proxy).”

„Există o clasă specială în Java (java.lang.reflect.Proxy) care vă permite de fapt să construiți un obiect în timpul execuției programului (dinamic), fără a crea o clasă separată pentru acesta.”

„Este foarte ușor de făcut:”

Reader reader = (Reader)Proxy.newProxyInstance();

„Este deja ceva nou pentru mine!”

„Dar desigur, nu avem nevoie de un obiect fără metode. Avem nevoie ca obiectul să aibă metode și trebuie să facă ceea ce vrem. Java folosește o interfață specială pentru aceasta numită InvocationHandler , care poate intercepta toate apelurile de metodă . asociat cu obiectul proxy. Un obiect proxy poate fi creat numai folosind interfețe."

Invoke – este numele standard pentru o metodă sau o clasă a cărei sarcină principală este să apeleze pur și simplu o metodă.”

Handler – este numele standard pentru o clasă care se ocupă de un anumit eveniment. De exemplu, o clasă care gestionează clicurile mouse-ului s-ar numi MouseClickHandler etc.”

„Interfața InvocationHandler are o singură metodă de invocare, către care sunt direcționate toate apelurile către obiectul proxy . De exemplu:”

Cod
Reader reader = (Reader)Proxy.newProxyInstance(new CustomInvocationHandler());
reader.close();
class CustomInvocationHandler implements InvocationHandler
{
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  System.out.println("yes!");
  return null;
 }
}

„Când apelați metoda cititorului . close (), metoda invocare va fi apelată, iar ecranul va afișa „da!””

„Așadar, am declarat o clasă CustomInvocationHandler și am implementat interfața InvocationHandler și metoda sa de invocare . Când metoda de invocare este apelată, afișează „da!”. Apoi am creat un obiect CustomInvocationHandler și l-am transmis metodei newProxyInstance când am creat un obiect proxy.”

— Da, totul este corect.

„Acesta este un instrument foarte puternic. De obicei, aceste proxy sunt create pentru a simula obiecte din programe care rulează fizic pe alt computer.  Sau pentru a controla accesul.”

„Puteți verifica permisiunile utilizatorului curent, puteți gestiona erorile, erorile de jurnal și multe altele în această metodă.”

„Iată un exemplu în care metoda invoke apelează și metodele obiectului original:”

Cod
Reader original = new UserCustomReader();

Reader reader = (Reader)Proxy.newProxyInstance(new CustomInvocationHandler(original));
reader.close();
class CustomInvocationHandler implements InvocationHandler
{
 private Reader readerOriginal;

 CustomInvocationHandler(Reader readerOriginal)
 {
  this.readerOriginal = readerOriginal;
 }

 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  if (method.getName().equals("close"))
  {
   System.out.println("Reader closed!");
  }

  // This calls the readerOriginal object's close method.
  // The method's name and a description of its parameters are stored in the method variable.
  return method.invoke(readerOriginal, args);
 }
}

„Acest exemplu are două caracteristici speciale.”

„Mai întâi, obiectul Reader «original» este transmis constructorului și o referință la acesta este salvată în CustomInvocationHandler .

„În al doilea rând, numim aceeași metodă din nou în metoda invoke, dar de data aceasta pe obiectul «original».

"Ah. Cu alte cuvinte, această ultimă linie apelează la aceeași metodă, dar pe obiectul original:"

return method.invoke(readerOriginal, args);

"Da."

"Nu aș spune că este super evident, dar este totuși de înțeles. Sau așa pare."

„Genial. Apoi încă ceva. În metoda newProxyInstance, trebuie să transmiteți puțin mai multe informații de întreținere pentru a crea un obiect proxy. Dar, deoarece nu creăm obiecte proxy monstruoase, această informație este ușor de obținut din clasa originală în sine. "

„Iată un alt exemplu:”

Cod
Reader original = new UserCustomReader();

ClassLoader classLoader = original.getClass().getClassLoader();
Class<?>[] interfaces = original.getClass().getInterfaces();
CustomInvocationHandler invocationHandler = new CustomInvocationHandler(original);

Reader reader = (Reader)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
class CustomInvocationHandler implements InvocationHandler
{
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
 {
  return null;
 }
}

"Ah. ClassLoader și listă de interfețe. Acesta este ceva de la Reflection, nu-i așa?"

"Da."

— Înțeleg. Ei bine, cred că pot crea un obiect proxy primitiv, super simplu, dacă am nevoie vreodată de unul.

— Atunci du-te și verifică-l cu Diego.