"Hallo Amigo."

"Hallo Rishi."

"Vandaag zal ik je een nieuw en zeer interessant onderwerp uitleggen: dynamische proxy's" .

"Java heeft verschillende manieren om de functionaliteit van een bepaalde klasse te wijzigen..."

"De eerste methode is overerving."

"De gemakkelijkste manier om het gedrag van een klasse te veranderen, is door een nieuwe klasse te maken die de oorspronkelijke (basis)klasse overneemt en de methoden ervan overschrijft. In plaats van de oorspronkelijke klasse te gebruiken, gebruikt u de afgeleide klasse. Bijvoorbeeld:"

Reader reader = new UserCustomReader();

"De tweede methode is het gebruik van een wrapper-klasse."

" BufferedReader is een voorbeeld van dit type klasse. Ten eerste erft het Reader . Met andere woorden, het kan worden gebruikt in plaats van Reader. Ten tweede leidt het alle oproepen om naar het oorspronkelijke Reader- object, dat moet worden doorgegeven aan de constructor van het BufferedReader-object. . Bijvoorbeeld:"

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

"De derde methode is om een ​​dynamische proxy (Proxy) te maken."

"Er is een speciale klasse in Java (java.lang.reflect.Proxy) waarmee je daadwerkelijk een object kunt construeren tijdens de uitvoering van een programma (dynamisch), zonder er een aparte klasse voor te maken."

"Dit is heel gemakkelijk om te doen:"

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

"Dat is al iets nieuws voor mij!"

"Maar we hebben natuurlijk geen object zonder methoden nodig. We hebben het object nodig om methoden te hebben, en we hebben ze nodig om te doen wat we willen. Java gebruikt hiervoor een speciale interface genaamd InvocationHandler , die alle methodeaanroepen kan onderscheppen . gekoppeld aan het proxy-object. Een proxy-object kan alleen worden gemaakt met behulp van interfaces."

" Invoke - is de standaardnaam voor een methode of klasse waarvan de primaire taak is om simpelweg een methode aan te roepen."

" Handler - is de standaardnaam voor een klasse die een bepaalde gebeurtenis afhandelt. Een klasse die muisklikken afhandelt, wordt bijvoorbeeld MouseClickHandler genoemd, enz."

"De InvocationHandler-interface heeft een enkele invoke-methode, waarnaar alle oproepen naar het proxy-object worden doorgestuurd . Bijvoorbeeld:"

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

"Bij het aanroepen van de reader . close () methode, wordt de invoke- methode aangeroepen en wordt op het scherm 'yes!' weergegeven."

"Dus hebben we een CustomInvocationHandler- klasse gedeclareerd en de InvocationHandler- interface en de bijbehorende invoke -methode geïmplementeerd. Wanneer de invoke-methode wordt aangeroepen, wordt 'yes!' weergegeven. Vervolgens hebben we een CustomInvocationHandler- object gemaakt en dit doorgegeven aan de newProxyInstance -methode bij het maken een proxy-object."

"Ja, dat klopt allemaal."

"Dit is een zeer krachtige tool. Meestal worden deze proxy's gemaakt om objecten te simuleren in programma's die fysiek op een andere computer draaien.  Of om de toegang te controleren."

"Met deze methode kunt u de machtigingen van de huidige gebruiker controleren, fouten afhandelen, fouten loggen en nog veel meer."

"Hier is een voorbeeld waarbij de invoke-methode ook de methoden van het oorspronkelijke object aanroept:"

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

"Dit exemplaar heeft twee bijzondere kenmerken."

"Eerst wordt het «originele» Reader- object doorgegeven aan de constructor, en een verwijzing daarnaar wordt opgeslagen in de CustomInvocationHandler ."

"Ten tweede roepen we dezelfde methode opnieuw aan in de invoke-methode, maar deze keer op het «oorspronkelijke» object."

"Ah. Met andere woorden, deze laatste regel roept dezelfde methode aan, maar dan op het originele object:"

return method.invoke(readerOriginal, args);

"Ja."

"Ik zou niet zeggen dat het super voor de hand liggend is, maar het is nog steeds begrijpelijk. Tenminste, zo lijkt het."

"Geweldig. Dan nog een ding. In de newProxyInstance-methode moet je wat meer huishoudelijke informatie doorgeven om een ​​proxy-object te maken. Maar aangezien we geen monsterlijke proxy-objecten maken, kan deze informatie gemakkelijk worden verkregen uit de oorspronkelijke klasse zelf. "

"Hier is nog een voorbeeld:"

Code
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 en lijst met interfaces. Dit is iets van Reflection, nietwaar?"

"Ja."

"Ik begrijp het. Nou, ik denk dat ik een primitief, supereenvoudig proxy-object kan maken als ik er ooit een nodig heb."

'Ga dan inchecken bij Diego.'