Conceptos del Patrón Proxy
El patrón proxy permite controlar el acceso a un objeto mediante un intermediario, añadiendo funcionalidades sin alterar el objeto principal. Se compone de tres elementos:
- Sujeto: Define la interfaz común para el objeto real y su proxy
- Sujeto Real: Implementa la lógica principal de negocio
- Proxy: Actúa como intermediario y añade funcionalidades adicoinales
Proxy Estático
Ejemplo básico con interfaz común:
public interface Movible {
void mover();
}
public class Perro implements Movible {
@Override
public void mover() {
System.out.println("Perro moviéndose...");
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Proxy para medición de tiempo:
public class ProxyTiempo implements Movible {
private final Movible objetivo;
public ProxyTiempo(Movible objetivo) {
this.objetivo = objetivo;
}
@Override
public void mover() {
long inicio = System.currentTimeMillis();
objetivo.mover();
long fin = System.currentTimeMillis();
System.out.println("Tiempo de movimiento: " + (fin - inicio) + "ms");
}
}
Limitaciones
- Requiere múltiples proxies para diferentes clases
- Duplicación de lógica en métodos múltiples
Proxy Dinámico con JDK
Requiere interfaces y manejo mediante invocation handlers:
public interface Operaciones {
void guardar();
void borrar();
}
public class ProxyDinamico implements InvocationHandler {
private final Object objetivo;
public ProxyDinamico(Object objetivo) {
this.objetivo = objetivo;
}
@Override
public Object invoke(Object proxy, Method metodo, Object[] args) throws Throwable {
System.out.println("Inicio: " + new Date());
Object resultado = metodo.invoke(objetivo, args);
System.out.println("Fin: " + new Date());
return resultado;
}
}
Implementación
Operaciones instancia = (Operaciones) Proxy.newProxyInstance(
OperacionesImpl.class.getClassLoader(),
new Class[]{Operaciones.class},
new ProxyDinamico(new OperacionesImpl())
);
instancia.guardar();
Proxy con CGLIB
Alternativa para clases sin interfaces mediante herencia:
public class InterceptorLog implements MethodInterceptor {
@Override
public Object intercept(Object objeto, Method metodo, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Inicio: " + new Date());
Object resultado = proxy.invokeSuper(objeto, args);
System.out.println("Fin: " + new Date());
return resultado;
}
}
public class Cliente {
public static void main(String[] args) {
Enhancer mejorador = new Enhancer();
mejorador.setSuperclass(Producto.class);
mejorador.setCallback(new InterceptorLog());
Producto proxy = (Producto) mejorador.create();
proxy.guardar();
}
}
Comparativa
| JDK | CGLIB |
|---|---|
| Requiere interfaces | Funciona con clases concretas |
| Generación más rápida | Mayor overhead inicial |
| No requiere dependencias externas | Necesita biblioteca CGLIB |
| Limitado a métodos de interfaz | Proxy de clases completas |