"Hej, Amigo."

"Hej, Rishi."

"I dag vil jeg forklare dig et nyt og meget interessant emne: dynamiske proxyer" .

"Java har flere måder at ændre funktionaliteten af ​​en bestemt klasse på..."

"Den første metode er arv."

"Den nemmeste måde at ændre en klasses adfærd på er at oprette en ny klasse, der arver den oprindelige (basis)klasse og tilsidesætte dens metoder. Så, i stedet for at bruge den originale klasse, bruger du den afledte klasse. For eksempel:"

Reader reader = new UserCustomReader();

"Den anden metode er at bruge en indpakningsklasse."

" BufferedReader er et eksempel på denne type klasse. For det første arver den Reader . Med andre ord kan den bruges i stedet for Reader. For det andet omdirigerer den alle kald til det originale Reader- objekt, som skal videregives til BufferedReader-objektets konstruktør . For eksempel:"

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

"Den tredje metode er at oprette en dynamisk proxy (Proxy)."

"Der er en speciel klasse i Java (java.lang.reflect.Proxy), som faktisk lader dig konstruere et objekt under programafvikling (dynamisk), uden at oprette en separat klasse til det."

"Dette er meget nemt at gøre:"

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

"Det er allerede noget nyt for mig!"

"Men selvfølgelig har vi ikke brug for et objekt uden metoder. Vi har brug for, at objektet har metoder, og vi har brug for dem til at gøre, hvad vi vil. Java bruger en speciel grænseflade til dette kaldet InvocationHandler , som kan opsnappe alle metodekald knyttet til proxy-objektet. Et proxy-objekt kan kun oprettes ved hjælp af grænseflader."

" Invoke – er standardnavnet for en metode eller klasse, hvis primære opgave er blot at kalde en metode."

" Handler – er standardnavnet for en klasse, der håndterer en eller anden begivenhed. For eksempel vil en klasse, der håndterer museklik hedde MouseClickHandler, osv.."

"InvocationHandler-grænsefladen har en enkelt invoke-metode, som alle kald til proxy-objektet er dirigeret til . For eksempel:"

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

"Når du kalder læseren . close ()-metoden, vil invoke- metoden blive kaldt, og skærmen vil vise 'yes!'"

"Så vi erklærede en CustomInvocationHandler, klasse og implementerede InvocationHandler- grænsefladen og dens invoke -metode. Når invoke-metoden kaldes, viser den 'yes!'. Derefter oprettede vi et CustomInvocationHandler- objekt og sendte det til newProxyInstance -metoden, da vi oprettede et proxyobjekt."

"Ja, det er alt sammen korrekt."

"Dette er et meget kraftfuldt værktøj. Normalt er disse proxyer skabt til at simulere objekter i programmer, der fysisk kører på en anden computer.  Eller for at kontrollere adgangen."

"Du kan kontrollere den aktuelle brugers tilladelser, håndtere fejl, logfejl og meget mere i denne metode."

"Her er et eksempel, hvor invoke-metoden også kalder det originale objekts metoder:"

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

"Dette eksempel har to specielle funktioner."

"Først sendes det «originale» Reader- objekt til konstruktøren, og en reference til det gemmes inde i CustomInvocationHandler ."

"For det andet kalder vi denne samme metode igen i invoke-metoden, men på det "originale" objekt denne gang."

"Ah. Med andre ord kalder denne sidste linje den samme metode, men på det originale objekt:"

return method.invoke(readerOriginal, args);

"Ja."

"Jeg vil ikke sige, at det er super indlysende, men det er stadig forståeligt. Eller det ser det ud til."

"Fantastisk. Så en ting mere. I newProxyInstance-metoden skal du videregive lidt flere husholdningsoplysninger for at oprette et proxy-objekt. Men da vi ikke opretter monstrøse proxy-objekter, kan disse oplysninger nemt hentes fra selve den originale klasse. "

"Her er et andet eksempel:"

Kode
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 og liste over grænseflader. Dette er noget fra Reflection, ikke?"

"Ja."

"Jeg forstår det. Tja, jeg tror, ​​jeg kan skabe et primitivt, super simpelt proxy-objekt, hvis jeg nogensinde får brug for et."

"Så gå og tjek ind med Diego."