Command Palette

Search for a command to run...

ES·EN

Nivel 2 · 20 min

Spring DI

El contenedor IoC de Spring es la base del ecosistema Spring. Entender el ciclo de vida de los beans, los estilos de inyección, los scopes y los proxies AOP es esencial para diagnosticar bugs misteriosos de Spring — dependencias nulas, errores de dependencias circulares y advice que silenciosamente no se dispara.

Contenedor IoC y ciclo de vida del bean

El contenedor IoC de Spring gestiona la creación, el cableado y la destrucción de beans. Ciclo de vida del bean: 1) El contenedor lee la configuración (anotaciones/XML), 2) Instancia del bean creada (constructor), 3) Dependencias inyectadas, 4) @PostConstruct llamado (init personalizado), 5) Bean listo para usar, 6) Al apagar: @PreDestroy llamado, 7) Bean destruido. ApplicationContext es el contenedor principal.

@Autowired vs inyección por constructor, Scopes de beans

La inyección por constructor es preferida sobre la inyección de campos con @Autowired por tres razones: 1) Los campos pueden declararse final (garantía de inmutabilidad), 2) La inyección por constructor hace las dependencias explícitas y visibles, 3) La inyección por constructor permite unit testing sin contenedor Spring. Scopes de beans: singleton (una instancia por contenedor, por defecto), prototype (nueva instancia por punto de inyección), request (uno por solicitud HTTP), session (uno por sesión HTTP).

Proxies AOP y dependencias circulares

Spring AOP funciona envolviendo beans en proxies CGLIB o JDK dinámicos. Por eso la auto-invocación no dispara el advice (@Transactional en un método que llama a otro método @Transactional en la misma clase es un error común — la segunda llamada va a través de this, no del proxy). Dependencias circulares: Spring puede resolver dependencias circulares entre beans singleton usando inyección de setters o campos. Las dependencias circulares por constructor fallan en el inicio.

Puntos clave

  • Preferí la inyección por constructor: habilita campos final, hace visibles las dependencias y permite testing sin Spring.
  • @Transactional solo funciona si la llamada va a través del proxy de Spring. La auto-invocación (this.method()) bypasea el proxy y la transacción.
  • Singleton es el scope por defecto. Inyectar un bean prototype en un singleton requiere manejo especial (ObjectProvider o @Lookup).

Code example

// PREFERIDO: inyección por constructor
@Service
public class OrderService {
  private final PaymentService payment;
  private final InventoryService inventory;

  public OrderService(PaymentService payment, InventoryService inventory) {
    this.payment = payment;
    this.inventory = inventory;
  }
}

// Hooks del ciclo de vida
@Component
public class CacheService {
  @PostConstruct
  public void init() { /* calentar cache */ }

  @PreDestroy
  public void cleanup() { /* vaciar cache */ }
}

// Prototype en singleton via ObjectProvider
@Service
public class TaskRunner {
  private final ObjectProvider<Worker> workerProvider;

  public void run() {
    Worker w = workerProvider.getObject();
    w.execute();
  }
}