Contenido del curso

Inyección de dependencias con Spring IoC

Resumen

Si estás aprendiendo Spring Boot, hay dos piezas que necesitas dominar antes que cualquier otra cosa: la inyección de dependencias y el contenedor IoC. Entender cómo se conectan te permite escribir código más limpio, fácil de probar y alineado con buenas prácticas profesionales.

Qué es la inyección de dependencias en Spring Boot

La inyección de dependencias es un patrón de diseño en el que los objetos que una clase necesita se le entregan desde fuera, en lugar de que ella misma los cree. Esto hace que tu clase sea más flexible y mucho más fácil de testear.

Imagina que tu controlador necesita un repositorio para acceder a datos. En vez de instanciarlo dentro, Spring se lo pasa ya construido. Tú te concentras en la lógica, no en armar el rompecabezas de objetos.

¿Qué es la inyección de dependencias? Es un patrón donde una clase recibe los objetos que necesita desde fuera, en lugar de crearlos internamente. Resultado: menos acoplamiento y código más mantenible.

Cómo funciona el contenedor IoC de Spring

La magia detrás de todo esto es la inversión de control, un principio de diseño en el que las clases delegan a un contenedor externo la responsabilidad de crear sus dependencias. En Spring, ese contenedor es el Spring IoC container.

El contenedor escanea tu proyecto, detecta qué clases deben gestionarse y las convierte en objetos llamados beans. Después, identifica qué bean depende de cuál y los inyecta automáticamente donde haga falta.

Qué anotaciones detecta Spring automáticamente

Para que Spring sepa qué clases registrar dentro de su contenedor, debes marcarlas con anotaciones específicas:

  • @Repository: para clases de acceso a datos.
  • @Service: para la capa de lógica de negocio.
  • @Controller o @RestController: para exponer endpoints web.
  • @Component: anotación genérica para cualquier componente.

Cuando Spring detecta cualquiera de estas, crea el bean y lo gestiona por ti. Tú nunca llamas al constructor manualmente.

Por qué usar inyección por constructor en lugar de @Autowired en el campo

Dentro de un MovieController, por ejemplo, puedes ver cómo un CrudMovieEntity se inyecta directamente en el constructor. Gracias a @RestController, ese componente entra al contenedor IoC y la dependencia llega lista para usarse, sin que tú instancies nada.

Existe otra forma: declarar el atributo y poner @Autowired encima. Funciona, pero el propio IDE te lo advierte: la inyección por campo no es recomendada. La forma ideal es siempre por constructor.

¿Cuál es la mejor forma de inyectar dependencias en Spring? Por constructor. Hace explícitas las dependencias, facilita las pruebas unitarias y evita los problemas de mutabilidad que trae la inyección por campo con @Autowired.

Un detalle útil: si solo tienes un constructor, ni siquiera necesitas escribir @Autowired. Spring lo resuelve automáticamente y tu código queda más limpio.

Qué beneficios trae trabajar así

Delegar la creación de objetos al contenedor te da ventajas concretas que se notan apenas crece el proyecto:

  • Evita acoplamientos innecesarios entre clases.
  • Hace el código más legible y fácil de mantener.
  • Promueve los principios SOLID de forma natural.
  • Facilita escribir tests porque puedes sustituir dependencias.

Hay una frase que vale la pena tatuarse como desarrollador: busca siempre bajo acoplamiento y alta cohesión. La inyección de dependencias es una de las herramientas que te lleva ahí casi sin esfuerzo.

Cómo se ve esto en un proyecto real con @Value y @Service

En un HelloController, por ejemplo, puedes usar @Value para acceder a una variable de configuración, y también inyectar un servicio anotado con @Service. Ese servicio, dentro de un proyecto como Platzi Play, vive dentro del contenedor IoC igual que cualquier otro componente.

Es decir, todas las piezas conviven en el mismo ecosistema: controladores, servicios, repositorios y configuraciones. Spring las conecta por ti según las anotaciones que encuentra.

Ahora bien, si desde tu MovieController estás llamando directamente al CrudRepository, técnicamente funciona, pero no es la mejor práctica. La meta no es escribir código que solo funcione, sino código que funcione bien. El siguiente paso natural es aplicar el patrón DataMapper para orientar tu API al dominio. ¿Tú prefieres inyectar por constructor o por campo? Cuéntame en los comentarios.