CodeGym /Cursos /Módulo 5. Spring /Arquitectura de Spring: IoC, DI, Spring Beans

Arquitectura de Spring: IoC, DI, Spring Beans

Módulo 5. Spring
Nivel 1 , Lección 1
Disponible

Hoy vamos a ver los tres pilares sobre los que se construye Spring: IoC (inversión de control), DI (inyección de dependencias) y Spring Beans. Todo esto suena a magia, pero en realidad — son los mejores amigos de cualquier desarrollador Java.

1. Inversión de control (Inversion of Control)

Recordemos la buena y vieja programación orientada a objetos. En OOP muchas veces pasa que un objeto depende de otro. Normalmente el desarrollador crea el objeto dependiente directamente en el código:


public class Car {
    private Engine engine;

    public Car() {
        this.engine = new Engine();
    }
}

Parece que funciona, pero hay un problema: has "acoplado fuertemente" el objeto Car con el objeto Engine. Si necesitas poner otro tipo de motor, por ejemplo ElectricEngine, tendrás que meterte en el código de Car y cambiarlo. No es muy cómodo, y además puedes romper algo por accidente. ¡Ese cambio viola el principio de flexibilidad y mantenibilidad del código!

Y aquí entra en escena IoC (Inversion of Control). La idea es sencilla: en vez de que el objeto cree su dependencia (Engine en nuestro caso), la responsabilidad de esa tarea la pasa al contenedor.

Contenedor IoC en Spring

Spring proporciona su IoC-container, que se encarga de crear, configurar y gestionar el ciclo de vida de los objetos. Tú solo tienes que describir las dependencias (mostraremos cómo). Esto permite deshacer el acoplamiento fuerte y centrarte en la lógica de negocio, no en crear objetos.

Ejemplo:


public class Car {
    private Engine engine;

    // La dependencia se pasa por el constructor
    public Car(Engine engine) {
        this.engine = engine;
    }
}

Ahora Car no sabe qué tipo de Engine recibirá. Eso lo decide el contenedor IoC, liberándonos de esa preocupación. En este código no aparece el contenedor IoC en sí — es solo un ejemplo de clase preparada para usarse con un IoC-container.

2. Dependency Injection (DI): la clave para gestionar dependencias

Dependency Injection (DI) es la forma de implementar IoC. El contenedor de Spring inyecta las dependencias (por ejemplo, Engine) en el objeto que las necesita (Car), usando uno de estos enfoques:

  1. A través del constructor.
  2. A través del setter (método).
  3. A través del campo (anotación).

En la práctica DI parece magia. Por ejemplo, así:


@Component
public class Engine {
    // Clase de Engine
}

@Component
public class Car {
    private Engine engine;

    // Spring inyectará automáticamente la dependencia vía constructor
    @Autowired
    public Car(Engine engine) {
        this.engine = engine;
    }
}

Spring detecta que la clase Car depende de Engine, crea automáticamente el Engine y se lo pasa a Car. ¡No tienes que preocuparte por crear o pasar los objetos!


3. Spring Beans: construyendo la magia de forma controlada

Spring Bean es un objeto gestionado por el IoC-container. El contenedor crea los beans, los configura, resuelve sus dependencias y gestiona su ciclo de vida. Si necesitas un objeto, le pides al contenedor: "Oye, ¡dame un bean!", y él se encarga.

Puedes convertir una clase en un bean marcándola con anotaciones especiales:

  • @Component — anotación genérica para crear beans.
  • @Service — marca beans que contienen lógica de negocio.
  • @Repository — para beans que trabajan con datos (por ejemplo repositorios JPA).
  • @Controller — para beans que manejan peticiones HTTP (en el contexto de Spring MVC).

Ejemplo de creación de un bean


@Component
public class Engine {
    // Este es un bean de Spring. Ahora el contenedor gestionará este objeto.
}

@Component
public class Car {
    private final Engine engine;

    @Autowired // Decimos a Spring que inyecte automáticamente la dependencia
    public Car(Engine engine) {
        this.engine = engine;
    }
}

4. Formas de inyección de dependencias

Ahora vamos a ver las tres formas principales de inyectar dependencias usando DI.

  1. Inyección por constructor

Este enfoque es preferible porque hace las dependencias explícitas e inmutables. Ejemplo:


@Component
public class Car {
    private final Engine engine;

    @Autowired
    public Car(Engine engine) {
        this.engine = engine;
    }
}
  1. Inyección mediante setter

La ventaja es la flexibilidad: puedes cambiar la dependencia después de crear el objeto. El inconveniente es que puede dejar el objeto en un estado mutable, lo cual no siempre es deseable.


@Component
public class Car {
    private Engine engine;

    @Autowired
    public void setEngine(Engine engine) {
        this.engine = engine;
    }
}
  1. Inyección por campo (anotaciones)

Es el método más debatido porque rompe la encapsulación. Pero para casos simples es totalmente viable.


@Component
public class Car {
    @Autowired
    private Engine engine;
}

5. Ciclo de vida de los Spring Beans

  1. Creación — el contenedor crea el objeto.
  2. Inicialización — el contenedor inyecta dependencias y llama métodos como @PostConstruct.
  3. Uso — el bean está listo para funcionar.
  4. Destrucción — el contenedor finaliza el bean y llama métodos como @PreDestroy.

Métodos para gestionar el ciclo de vida:

  • @PostConstruct — se llama después de crear el bean y completar DI.
  • @PreDestroy — se llama antes de destruir el bean.

Ejemplo de código:


@Component
public class Car {

    @PostConstruct
    public void init() {
        System.out.println("Car is ready to drive!");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Car is being destroyed...");
    }
}

6. Errores comunes al trabajar con IoC y DI

No te preocupes, los errores le pasan a todos. Un caso clásico: olvidaste marcar la clase Engine con la anotación @Component. Por eso Spring no puede encontrar el bean:


Error creating bean with name 'car': Unsatisfied dependency expressed through constructor

Pista: revisa si todas las dependencias están "incluidas" en el contexto, es decir, si tienen anotaciones como @Component.

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