Java Reflection-dynamiska proxyservrar

använda Java Reflection du skapar dynamiska implementeringar av gränssnitt vid körning. Du gör det med klassen java.lang.reflect.Proxy. Namnet på den här klassen är därför jag hänvisar till dessa dynamiska gränssnittsimplementeringar som dynamiska proxyservrar. Dynamiska proxies kan användas för många olika ändamål, t.ex. databasanslutning och transaktionshantering, dynamiska mock-objekt för enhetstestning och andra AOP-liknande metodavlyssningsändamål.

skapa proxyservrar

du skapar dynamiska proxyservrar med metoden Proxy.newProxyInstance(). Metoderna newProxyInstance() tar 3 parametrar:

  1. ClassLoader som är att “ladda” den dynamiska proxyklassen.
  2. en rad gränssnitt att implementera.
  3. An InvocationHandler för att vidarebefordra alla metoder anropar proxyn till.

här är ett exempel:

efter att ha kört den här koden innehåller variabeln proxy en dynamisk implementering av gränssnittet MyInterface. Alla samtal till proxy kommer att vidarebefordras till handler genomförandet av den allmänna InvocationHandler gränssnitt. InvocationHandler s omfattas i nästa avsnitt.

Invocationhandlers

som tidigare nämnts måste du skicka en InvocationHandler implementering till metoden Proxy.newProxyInstance(). Alla metodsamtal till den dynamiska proxyn vidarebefordras till denna InvocationHandler – implementering. Så här ser gränssnittet ut InvocationHandler :

public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object args) throws Throwable;}

här är ett exempel på implementering:

public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object args) throws Throwable { //do something "dynamic" }}

parametern proxy som skickas till metoden invoke() är det dynamiska proxyobjektet som implementerar gränssnittet. Oftast behöver du inte det här objektet.

Method – objektet som skickas in i invoke() – metoden representerar den metod som kallas på gränssnittet som dynamic proxy implementerar. Från objektet Method kan du få metodnamn, parametertyper, returtyp etc. Se texten på metoder för mer information.

Object args arrayen innehåller parametervärdena som skickas till proxyn när metoden i det implementerade gränssnittet anropades. Obs: primitiver (int, lång etc) i det implementerade gränssnittet är inslagna i sina objektmotsvarigheter (heltal, lång etc.).

kända användningsfall

dynamiska proxyer är kända för att användas för åtminstone följande ändamål:

  • databasanslutning och transaktionshantering
  • dynamiska Mock-objekt för enhetstestning
  • anpassning av Di-Behållare till anpassade Fabriksgränssnitt
  • AOP-liknande Metodavlyssning

databasanslutning och transaktionshantering

Spring framework har en transaktionsproxy som kan starta och begå / återställa en transaktion åt dig. Hur detta fungerar beskrivs mer detaljerat i texten avancerad anslutning och Transaktionsavgränsning och förökning , så jag beskriver det bara kortfattat. Samtalssekvensen blir något längs detta:

dynamiska Mock-objekt för enhetstestning

Butterfly Test Tools använder dynamiska proxies för att implementera dynamiska stubbar, mocks och proxies för enhetstestning. När du testar en klass A som använder en annan klass B (gränssnitt verkligen) kan du skicka en mock-implementering av B till A istället för en riktig B. Alla metodsamtal på B spelas nu in, och du kan ställa in vilka returvärden mock B ska returnera.

dessutom fjäril testverktyg kan du linda en riktig B i en mock B, så att alla metod samtal på mock registreras, och sedan vidarebefordras till den verkliga B. Detta gör det möjligt att kontrollera vilka metoder kallades på en verklig fungerande B. Till exempel, om att testa en DAO kan du linda databasanslutningen i en mock. DAO kommer inte att se skillnaden, och DAO kan läsa/skriva data till databasen som vanligt eftersom mock vidarebefordrar alla samtal till databasen. Men nu kan du kontrollera via mock om DAO använder anslutningen ordentligt, till exempel om connection.close() heter (eller inte kallas), om du förväntade dig det. Detta är normalt inte möjligt att bestämma från returvärdet för en DAO.

anpassning av Di-Behållare till anpassade Fabriksgränssnitt

dependency injection container Butterfly Container har en kraftfull funktion som gör att du kan injicera hela behållaren i bönor som produceras av den. Men eftersom du inte vill ha ett beroende av containergränssnittet kan behållaren anpassa sig till ett anpassat fabriksgränssnitt för din design. Du behöver bara gränssnittet. Inget genomförande. Således kan fabriksgränssnittet och din klass se ut så här:

public interface IMyFactory { Bean bean1(); Person person(); ...}

när klassen MyAction anropar metoder på instansen IMyFactory som injiceras i dess konstruktör av behållaren översätts metodanropen till anrop till metoden IContainer.instance(), vilket är den metod du använder för att hämta instanser från behållaren. På så sätt kan ett objekt använda Butterfly Container som en fabrik vid körning, snarare än att bara ha beroenden injicerade i sig själv vid skapandet. Och detta utan att ha några beroenden på någon fjäril Container specifika gränssnitt.

AOP-liknande Method Interception

Spring framework gör det möjligt att avlyssna metodsamtal till en viss böna, förutsatt att bean implementerar något gränssnitt. Vårramen sveper bönan i en dynamisk proxy. Alla samtal till bönan avlyssnas sedan av proxyn. Proxyn kan besluta att anropa andra metoder på andra objekt antingen före, i stället för, eller efter att delegera metoden anropet till bönan insvept.

Lämna ett svar

Din e-postadress kommer inte publiceras.