"Hej, Amigo."

"Hej Rishi."

"Idag kommer jag att förklara ett nytt och mycket intressant ämne för dig: dynamiska proxyservrar" .

"Java har flera sätt att ändra funktionaliteten för en viss klass..."

"Den första metoden är arv."

"Det enklaste sättet att ändra en klasss beteende är att skapa en ny klass som ärver den ursprungliga (bas) klassen, och åsidosätta dess metoder. Sedan, istället för att använda den ursprungliga klassen, använder du den härledda klassen. Till exempel:"

Reader reader = new UserCustomReader();

"Den andra metoden är att använda en omslagsklass."

" BufferedReader är ett exempel på den här typen av klass. För det första ärver den Reader . Med andra ord kan den användas istället för Reader. För det andra omdirigerar den alla anrop till det ursprungliga Reader- objektet, som måste skickas till BufferedReader-objektets konstruktor . Till exempel:"

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

"Den tredje metoden är att skapa en dynamisk proxy (Proxy)."

"Det finns en speciell klass i Java (java.lang.reflect.Proxy) som faktiskt låter dig konstruera ett objekt under programkörning (dynamiskt), utan att skapa en separat klass för det."

"Det här är väldigt enkelt att göra:"

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

"Det är redan något nytt för mig!"

"Men naturligtvis behöver vi inte ett objekt utan metoder. Vi behöver att objektet har metoder, och vi behöver dem för att göra vad vi vill. Java använder ett speciellt gränssnitt för detta som kallas InvocationHandler , som kan avlyssna alla metodanrop associerat med proxyobjektet. Ett proxyobjekt kan endast skapas med gränssnitt."

" Invoke – är standardnamnet för en metod eller klass vars primära uppgift är att helt enkelt anropa någon metod."

" Handler – är standardnamnet för en klass som hanterar en händelse. Till exempel skulle en klass som hanterar musklick kallas MouseClickHandler, etc."

"InvocationHandler-gränssnittet har en enkel anropsmetod, till vilken alla anrop till proxyobjektet riktas . Till exempel:"

Koda
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 anropar läsaren . close ()-metoden kommer anropsmetoden att anropas och skärmen visar 'yes!'"

"Så, vi deklarerade en CustomInvocationHandler, klass och implementerade InvocationHandler- gränssnittet och dess anropsmetod . När anropsmetoden anropas visar den 'yes!'. Sedan skapade vi ett CustomInvocationHandler -objekt och skickade det till newProxyInstance -metoden när vi skapade ett proxyobjekt."

"Ja, det är helt rätt."

"Det här är ett mycket kraftfullt verktyg. Vanligtvis skapas dessa proxyservrar för att simulera objekt i program som fysiskt körs på en annan dator.  Eller för att kontrollera åtkomst."

"Du kan kontrollera den aktuella användarens behörigheter, hantera fel, logga fel och mycket mer med den här metoden."

"Här är ett exempel där invoke-metoden också anropar det ursprungliga objektets metoder:"

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

"Det här exemplet har två speciella egenskaper."

"Först skickas det «originala» Reader -objektet till konstruktorn och en referens till det sparas i CustomInvocationHandler ."

"För det andra kallar vi samma metod igen i anropsmetoden, men på det "ursprungliga" objektet den här gången."

"Ah. Med andra ord, den här sista raden anropar samma metod, men på det ursprungliga objektet:"

return method.invoke(readerOriginal, args);

"Japp."

"Jag skulle inte säga att det är superuppenbart, men det är ändå förståeligt. Eller så verkar det."

"Bra. Sedan en sak till. I metoden newProxyInstance måste du skicka lite mer hushållsinformation för att skapa ett proxyobjekt. Men eftersom vi inte skapar monstruösa proxyobjekt, erhålls denna information lätt från själva originalklassen. "

"Här är ett annat exempel:"

Koda
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 och lista över gränssnitt. Det här är något från Reflection, eller hur?"

"Japp."

"Jag förstår. Tja, jag tror att jag kan skapa ett primitivt, superenkelt proxyobjekt om jag någonsin behöver ett."

"Gå då och kolla in med Diego."