CodeGym /Cursos /Módulo 5. Spring /Introducción a los objetos proxy (Proxy) y cómo funcionan...

Introducción a los objetos proxy (Proxy) y cómo funcionan en Spring

Módulo 5. Spring
Nivel 3 , Lección 6
Disponible

Hoy vamos a profundizar en un tema importante, sin el cual no entenderás la verdadera magia de AOP en Spring: los objetos proxy (Proxy). Vamos a ver qué son, cómo funcionan y para qué sirven en Spring.

Si piensas que "proxy" es ese servidor sospechoso que usabas para saltarte el bloqueo de tu web favorita, estás... ¡en lo cierto! A medias. En programación los proxy cumplen un papel parecido: actúan como intermediarios. Solo que en lugar de saltar bloqueos, los objetos proxy en Spring añaden funcionalidad extra a tu código.

Se puede comparar con contratar a un asistente (proxy) para gestionar tu agenda. Cuando alguien quiere reunirse contigo, primero contacta a ese asistente. Él decide si merece la pena molestarte ahora. De forma similar, un objeto proxy en Spring puede interceptar llamadas a métodos, hacer algo útil (por ejemplo, logging o comprobaciones de seguridad) y luego delegar al objeto real.


¿Cómo funcionan los objetos proxy?

El núcleo de AOP en Spring es el uso de objetos proxy. Si añades un aspecto (por ejemplo, con @Aspect), Spring crea dinámicamente un objeto proxy que sustituye al bean original. Cuando se llama a un método en ese bean, la llamada pasa primero por el proxy y solo después llega al método objetivo.

Flujo de ejecución:

  1. Llamas a un método en tu bean.
  2. El objeto proxy intercepta la llamada.
  3. El proxy ejecuta su "código adicional" (por ejemplo, logging, comprobación de transacciones).
  4. El proxy delega la ejecución al método objetivo de tu bean.

Tipos de proxy en Spring

Spring soporta dos tipos de proxy:

  1. JDK Dynamic Proxy — funciona con interfaces.
  2. CGLIB Proxy — funciona con clases.

JDK Dynamic Proxy

JDK Dynamic Proxy crea objetos proxy solo para interfaces. Si tu clase implementa una interfaz, Spring generará un proxy usando JDK Dynamic Proxy.

Ejemplo:


public interface PaymentService {
    void processPayment();
}

@Component
public class PaymentServiceImpl implements PaymentService {
    @Override
    public void processPayment() {
        System.out.println("Processing payment...");
    }
}

En este caso Spring creará un proxy para la interfaz PaymentService. El proxy interceptará las llamadas al método processPayment().

CGLIB Proxy

Si tu bean no implementa interfaces, Spring usa CGLIB Proxy. Este tipo de proxy extiende (hereda) tu clase y sobrescribe métodos para añadir lógica extra.

Ejemplo:


@Component
public class NotificationService {
    public void sendNotification() {
        System.out.println("Sending notification...");
    }
}

Como la clase NotificationService no implementa interfaces, Spring generará un proxy usando CGLIB.

Importante: CGLIB no funciona con métodos marcados como final. ¿Por qué? Porque final impide sobrescribir el método, lo que rompe toda la lógica del proxy.


Ejemplo de uso de objetos proxy en AOP

Vamos a crear un ejemplo donde usamos un proxy para insertar logs al invocar un método.

Código sin AOP:


@Component
public class UserService {
    public void createUser(String username) {
        System.out.println("User " + username + " created!");
    }
}

Este código simplemente imprime un mensaje al crear un usuario. Pero si queremos loguear automáticamente cada llamada al método createUser, tendríamos que modificar el método. Eso rompe el principio de responsabilidad única.


Código con AOP y proxy:

Creando un aspecto:


@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.demo.UserService.createUser(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Method " + joinPoint.getSignature().getName() + " is called");
    }
}

Ahora, al invocar el método createUser, Spring usará un objeto proxy. El proxy ejecutará primero logBefore y solo después llamará a createUser.


¿Cómo ver el proxy "mágico" en acción?

Puedes ver cómo Spring crea objetos proxy con una prueba sencilla. Por ejemplo:


@Autowired
private UserService userService;

@Test
public void checkProxy() {
    System.out.println(userService.getClass());
}

La salida podría ser algo así:

  1. Para JDK Dynamic Proxy:
    
    class com.sun.proxy.$Proxy12
    
  2. Para CGLIB Proxy:
    
    class com.example.demo.UserService$$EnhancerBySpringCGLIB$$3f9b8a5f
    

Fíjate cómo Spring añade sus sufijos "mágicos" al nombre de la clase.


¿Por qué es importante entender los proxy?

Para trabajar eficazmente con AOP y evitar sorpresas, es importante entender cómo funcionan los proxy.

Errores típicos:

  • Llamadas a métodos dentro de la misma clase: Si llamas a un método desde otro método de la misma clase, AOP no funcionará. El proxy no podrá interceptar la llamada porque va directa, saltándose el proxy.

Ejemplo:


@Component
public class SampleService {

    public void externalMethod() {
        internalMethod(); // ¡El proxy no interceptará esto!
    }

    public void internalMethod() {
        System.out.println("Internal method called");
    }
}

Solución: separa los métodos en distintos beans.

  • Métodos final: Si usas CGLIB Proxy, declarar un método como final hará que el proxy no pueda sobrescribirlo. Eso también inutiliza AOP para ese método.

Ejemplo:


public final void finalMethod() {
    System.out.println("This method cannot be proxied");
}

Relevancia práctica

Entender cómo funcionan los proxy te ayuda a evitar errores y a tener un código más claro. En proyectos reales, los proxy se usan no solo para aspectos, sino también para gestionar transacciones y seguridad. Por ejemplo:

  • La anotación @Transactional en Spring también se basa en AOP y proxy. Si no entiendes que el proxy no funcionará al llamar a un método desde la misma clase, puedes obtener resultados inesperados, por ejemplo, que no se haga el rollback de la transacción.

Hemos visto que los objetos proxy juegan un papel clave en la implementación de AOP en Spring. Permiten añadir cross-cutting concerns (aspectos) sin cambiar la lógica de negocio. Spring usa dinámicamente JDK Dynamic Proxy y CGLIB Proxy según el bean concreto. Ahora tienes esta información y estás listo para usar aspectos de forma más profunda en tus aplicaciones.

Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION