Dynamiska proxyer med InvocationHandler
Skapa dynamiska JDK-proxyer för att fånga anrop till gränssnittsmetoder för loggning, cachning och nya försök.
Dynamiska proxyer med InvocationHandler är en gratis lektion i Java Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Java Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Java Academy innehåller totalt 4 lektioner.
Vad är en dynamisk proxy?
En dynamisk JDK-proxy är ett objekt som skapas under körning och implementerar ett eller flera gränssnitt. Alla metodanrop vidarebefordras till en InvocationHandler som du tillhandahåller.
Skapa en proxy med Proxy.newProxyInstance
Anropa Proxy.newProxyInstance(classLoader, interfaces[], handler) för att skapa en proxy. Proxyn implementerar alla angivna gränssnitt.
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LoggingHandler(realService)
);
proxy.findById(42L); // intercepted by LoggingHandlerGränssnittet InvocationHandler
Implementera InvocationHandler för att hantera varje metodanrop. Hanteraren tar emot proxyobjektet, den anropade metoden och argumenten.
public class LoggingHandler implements InvocationHandler {
private final Object target;
public LoggingHandler(Object target) { this.target = target; }
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">> " + method.getName());
Object result = method.invoke(target, args);
System.out.println("<< " + method.getName());
return result;
}
}Proxy för cachning
En InvocationHandler kan cacha resultat: om cachen innehåller ett resultat för argumenten returnerar den det; annars anropar den den riktiga metoden och sparar resultatet.
public class CachingHandler implements InvocationHandler {
private final Object target;
private final Map<String, Object> cache = new HashMap<>();
public CachingHandler(Object target) { this.target = target; }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String key = method.getName() + Arrays.toString(args);
return cache.computeIfAbsent(key, k -> {
try { return method.invoke(target, args); }
catch (Exception e) { throw new RuntimeException(e); }
});
}
}Proxy för försökslogik
Omslut metodanrop i en loop för nya försök. Om ett undantag inträffar gör du nya försök upp till N gånger innan undantaget kastas vidare.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
for (int attempt = 1; attempt <= 3; attempt++) {
try { return method.invoke(target, args); }
catch (InvocationTargetException e) {
if (attempt == 3) throw e.getCause();
Thread.sleep(1000L * attempt);
}
}
throw new RuntimeException("unreachable");
}Proxy för transaktionshantering
Spring:s @Transactional använder en dynamisk proxy för att starta en transaktion före ett metodanrop och genomföra eller återställa den efteråt — utan att anroparen märker det.
Kontrollera om ett objekt är en proxy
Använd Proxy.isProxyClass(obj.getClass()) för att identifiera proxyer och Proxy.getInvocationHandler(proxy) för att hämta hanteraren.
if (Proxy.isProxyClass(service.getClass())) {
InvocationHandler h = Proxy.getInvocationHandler(service);
System.out.println("Handler: " + h.getClass().getSimpleName());
}Begränsningar hos dynamiska JDK-proxyer
Dynamiska JDK-proxyer fungerar endast med gränssnitt — de kan inte skapa proxyer för konkreta klasser. För klassbaserade proxyer använder du CGLIB, som Spring också använder internt för klasser med @Configuration.
CGLIB som alternativ
CGLIB genererar en underklass av målklassen under körning och skriver över alla metoder som inte är final. Spring använder det när inga gränssnitt finns. Ingen annotering krävs — det sker transparent.
Proxyer i Hibernate
Hibernate laddar lata entitetsrelationer med CGLIB-/Byte Buddy-proxyer. När du kommer åt en lat samling skickar proxyn en SQL-fråga.
// Hibernate creates a proxy for:
@ManyToOne(fetch = FetchType.LAZY)
private Department department;
// Accessing dept triggers a DB query via the proxyProxyers prestanda
Metoddispat‑chning via en dynamisk proxy är ungefär 5–10 gånger långsammare än ett direkt anrop. För mycket prestandakritiska kodvägar kan du överväga kodgenerering vid kompilering (APT) eller MethodHandles i stället för dynamiska proxyer.
Snabbkontroll
Vilken är den huvudsakliga begränsningen hos dynamiska JDK-proxyer?
Sammanfattning
Dynamiska JDK-proxyer fångar upp metodanrop på gränssnitt via InvocationHandler. Använd dem för loggning, cachning, nya försök och transaktionshantering. För proxyer av klasser använder du CGLIB. Cacha skapandet av proxyer — det bygger på reflektion och är inte kostnadsfritt.
Lär dig Java med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 104
- Lektioner
- 374
Vanliga frågor
Är lektionen ”Dynamiska proxyer med InvocationHandler” gratis?
Ja – hela texten till ”Dynamiska proxyer med InvocationHandler” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Java Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Java Academy innehåller totalt 4 lektioner.
Vad lär jag mig i ”Dynamiska proxyer med InvocationHandler”?
Skapa dynamiska JDK-proxyer för att fånga anrop till gränssnittsmetoder för loggning, cachning och nya försök. Ni övar på Java Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Java Academy?
Du behöver inga förkunskaper. Utbildningen i Java Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.
Hur lång tid tar lektionen ”Dynamiska proxyer med InvocationHandler”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Java Academy-lektionen?
Ja. Varje Java Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Inspektera klasser med reflection
- Anropa metoder och få åtkomst till fält
- Dynamiska proxyer med InvocationHandler
- Reflektionsprestanda och alternativ