Proxies dinámicos con InvocationHandler
Cree proxies dinámicos de JDK para interceptar llamadas a métodos de interfaces destinadas al registro, el almacenamiento en caché y los reintentos.
Proxies dinámicos con InvocationHandler es una lección gratuita de Java Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Java Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Java Academy incluye 4 lecciones en total.
¿Qué es un proxy dinámico?
Un proxy dinámico de JDK es un objeto creado durante la ejecución que implementa una o varias interfaces. Todas las llamadas a métodos se reenvían a un InvocationHandler proporcionado por usted.
Creación de un proxy con Proxy.newProxyInstance
Llame a Proxy.newProxyInstance(classLoader, interfaces[], handler) para crear un proxy. El proxy implementa todas las interfaces indicadas.
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LoggingHandler(realService)
);
proxy.findById(42L); // intercepted by LoggingHandlerLa interfaz InvocationHandler
Implemente InvocationHandler para gestionar cada llamada a un método. El handler recibe el objeto proxy, el método invocado y los argumentos.
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 para el almacenamiento en caché
Un InvocationHandler puede almacenar resultados en caché: si la caché contiene un resultado para los argumentos, lo devuelve; de lo contrario, llama al método real y almacena el resultado.
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 para la lógica de reintentos
Envuelva las llamadas a métodos en un bucle de reintentos. Si se produce una excepción, reintente hasta N veces antes de volver a lanzarla.
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 para la gestión de transacciones
La anotación @Transactional de Spring utiliza un proxy dinámico para iniciar una transacción antes de una llamada a un método y confirmarla o revertirla después, todo ello sin que la persona que realiza la llamada lo sepa.
Comprobación de si un objeto es un proxy
Utilice Proxy.isProxyClass(obj.getClass()) para detectar proxies y Proxy.getInvocationHandler(proxy) para recuperar el handler.
if (Proxy.isProxyClass(service.getClass())) {
InvocationHandler h = Proxy.getInvocationHandler(service);
System.out.println("Handler: " + h.getClass().getSimpleName());
}Limitaciones de los proxies dinámicos de JDK
Los proxies dinámicos de JDK solo funcionan con interfaces; no pueden crear proxies de clases concretas. Para crear proxies basados en clases, utilice CGLIB, que Spring también utiliza internamente para las clases @Configuration.
CGLIB como alternativa
CGLIB genera una subclase de la clase de destino durante la ejecución y sobrescribe todos los métodos que no sean final. Spring lo utiliza cuando no hay interfaces presentes. No requiere ninguna anotación: es transparente.
Proxy en Hibernate
Hibernate carga de forma diferida las asociaciones de entidades mediante proxies de CGLIB/Byte Buddy. Cuando accede a una colección de carga diferida, el proxy ejecuta una consulta SQL.
// Hibernate creates a proxy for:
@ManyToOne(fetch = FetchType.LAZY)
private Department department;
// Accessing dept triggers a DB query via the proxyRendimiento de los proxies
La resolución de métodos mediante un proxy dinámico es aproximadamente entre 5 y 10 veces más lenta que una llamada directa. Para las rutas más críticas, considere la generación de código en tiempo de compilación (APT) o MethodHandles en lugar de proxies dinámicos.
Comprobación rápida
¿Cuál es la principal limitación de los proxies dinámicos de JDK?
Resumen
Los proxies dinámicos de JDK interceptan llamadas a métodos de interfaces mediante InvocationHandler. Utilícelos para el registro, el almacenamiento en caché, los reintentos y la gestión de transacciones. Para crear proxies de clases, utilice CGLIB. Almacene en caché la creación de proxies: es una operación reflectiva y no es gratuita.
Preguntas frecuentes
¿La lección «Proxies dinámicos con InvocationHandler» es gratis?
Sí — el texto completo de «Proxies dinámicos con InvocationHandler» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Java Academy, actualiza a CoddyKit PRO. El curso de Java Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Proxies dinámicos con InvocationHandler»?
Cree proxies dinámicos de JDK para interceptar llamadas a métodos de interfaces destinadas al registro, el almacenamiento en caché y los reintentos. Practicas Java Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar Java Academy?
No se requiere experiencia previa. Java Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.
¿Cuánto tiempo toma la lección «Proxies dinámicos con InvocationHandler»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de Java Academy?
Sí. Cada lección de Java Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Inspección de clases con Reflection
- Invocación de métodos y acceso a campos
- Proxies dinámicos con InvocationHandler
- Rendimiento de Reflection y alternativas