"Hei, Amigo."

"Hei, Rishi."

"I dag vil jeg forklare et nytt og veldig interessant emne for deg: dynamiske proxyer" .

"Java har flere måter å endre funksjonaliteten til en bestemt klasse på..."

"Den første metoden er arv."

"Den enkleste måten å endre en klasses atferd på er å lage en ny klasse som arver den opprinnelige (base) klassen, og overstyre metodene. Så, i stedet for å bruke den opprinnelige klassen, bruker du den avledede klassen. For eksempel:"

Reader reader = new UserCustomReader();

"Den andre metoden er å bruke en innpakningsklasse."

" BufferedReader er et eksempel på denne typen klasse. For det første arver den Reader . Med andre ord kan den brukes i stedet for Reader. For det andre omdirigerer den alle kall til det originale Reader- objektet, som må sendes til BufferedReader-objektets konstruktør . For eksempel:"

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

"Den tredje metoden er å lage en dynamisk proxy (Proxy)."

"Det er en spesiell klasse i Java (java.lang.reflect.Proxy) som faktisk lar deg konstruere et objekt under programkjøring (dynamisk), uten å lage en egen klasse for det."

"Dette er veldig enkelt å gjøre:"

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

"Det er allerede noe nytt for meg!"

"Men selvfølgelig trenger vi ikke et objekt uten metoder. Vi trenger at objektet har metoder, og vi trenger at de gjør det vi vil. Java bruker et spesielt grensesnitt for dette kalt InvocationHandler , som kan avskjære alle metodekall . knyttet til proxy-objektet. Et proxy-objekt kan bare opprettes ved hjelp av grensesnitt."

" Invoke – er standardnavnet for en metode eller klasse hvis primæroppgave er å ganske enkelt kalle en metode."

" Handler – er standardnavnet for en klasse som håndterer en hendelse. For eksempel vil en klasse som håndterer museklikk bli kalt MouseClickHandler, etc."

"InvocationHandler-grensesnittet har en enkelt invoke-metode, som alle kall til proxy-objektet er rettet 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 kaller leseren . close ()-metoden, kalles påkallingsmetoden, og skjermen vil vise 'yes!'. "

"Så, vi erklærte en CustomInvocationHandler, klasse, og implementerte InvocationHandler- grensesnittet og dens invoke- metode. Når invoke-metoden kalles, viser den 'yes!'. Så opprettet vi et CustomInvocationHandler- objekt, og sendte det til newProxyInstance -metoden når vi opprettet et proxy-objekt."

"Ja, det er helt riktig."

"Dette er et veldig kraftig verktøy. Vanligvis lages disse proxyene for å simulere objekter i programmer som fysisk kjører på en annen datamaskin.  Eller for å kontrollere tilgangen."

"Du kan sjekke gjeldende brukers tillatelser, håndtere feil, loggfeil og mye mer i denne metoden."

"Her er et eksempel der invoke-metoden også kaller det originale objektets 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 eksemplet har to spesielle funksjoner."

"Først sendes det «originale» Reader- objektet til konstruktøren, og en referanse til det lagres inne i CustomInvocationHandler ."

"For det andre kaller vi denne samme metoden igjen i invoke-metoden, men på det «originale» objektet denne gangen."

"Ah. Med andre ord, denne siste linjen kaller den samme metoden, men på det opprinnelige objektet:"

return method.invoke(readerOriginal, args);

"Japp."

"Jeg vil ikke si at det er veldig åpenbart, men det er fortsatt forståelig. Eller så det virker."

"Flott. Så en ting til. I newProxyInstance-metoden må du sende litt mer husholdningsinformasjon for å lage et proxy-objekt. Men siden vi ikke lager monstrøse proxy-objekter, kan denne informasjonen enkelt hentes fra selve den opprinnelige klassen. "

"Her er et annet 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 grensesnitt. Dette er noe fra Reflection, er det ikke?"

"Japp."

"Jeg skjønner. Vel, jeg tror jeg kan lage et primitivt, superenkelt proxy-objekt hvis jeg noen gang trenger det."

"Så gå og sjekk inn med Diego."