1. Sumérgete en el ciclo de vida de los Spring Beans
Etapas principales del ciclo de vida de un Spring Bean:
- Creación (Initialization): el contenedor IoC crea el objeto (bean) y realiza la inyección de todas las dependencias.
- Inicialización (Post Initialization): se ejecutan operaciones adicionales, como la configuración y el arranque de procesos necesarios.
- Destrucción (Destruction): antes de que el contenedor termine su trabajo, el bean puede completar sus tareas, liberar recursos y hacer limpieza.
Vamos a ver cómo Spring gestiona estas etapas y qué herramientas ofrece para configurarlas.
2. ¿Cómo gestiona el ciclo de vida el contenedor IoC?
El contenedor IoC de Spring se encarga de:
- Crear objetos según la configuración o las anotaciones
- Inyectar dependencias en el bean
- Ejecutar métodos de inicialización
- Llamar a métodos de finalización cuando el bean deja de ser necesario
En una aplicación real esto sucede así:
- Spring crea el Bean
- Spring inyecta dependencias mediante DI (@Autowired, @Bean, @Component)
- Spring ejecuta métodos anotados con
@PostConstructdespués de crear el objeto - Al cerrar la aplicación, Spring llama a los métodos anotados con
@PreDestroypara terminar correctamente el objeto
3. Uso de anotaciones para manejar el ciclo de vida
Spring ofrece anotaciones cómodas para gestionar el ciclo de vida de un bean: @PostConstruct y @PreDestroy. Ahora lo vemos con más detalle.
@PostConstruct: método de inicialización
Esta anotación marca un método que se invoca después de crear el objeto y de inyectar las dependencias. Es perfecta para ajustes adicionales antes de usar el objeto.
Ejemplo:
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class CoffeeMaker {
@PostConstruct
public void heatUp() {
System.out.println("La cafetera se calienta...");
}
}
Cuando Spring crea el bean CoffeeMaker, llamará automáticamente al método heatUp después de que todas las dependencias estén configuradas.
@PreDestroy: método de finalización
Esta anotación indica el método que será llamado antes de destruir el objeto. Es útil para liberar recursos o ejecutar tareas finales.
Ejemplo:
import org.springframework.stereotype.Component;
import javax.annotation.PreDestroy;
@Component
public class CoffeeMaker {
@PreDestroy
public void shutDown() {
System.out.println("La cafetera se apaga...");
}
}
Cuando Spring termina la aplicación, el método shutDown se llamará automáticamente.
4. Configurar tus propios métodos para el ciclo de vida
A veces los métodos estándar no son suficientes y necesitas más flexibilidad. Spring ofrece dos maneras de añadir métodos personalizados para arrancar y cerrar beans.
Definir métodos en la configuración Java
Al usar la anotación @Bean puedes especificar métodos personalizados para inicialización y destrucción.
Ejemplo:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public CoffeeMaker coffeeMaker() {
return new CoffeeMaker();
}
}
class CoffeeMaker {
public void init() {
System.out.println("¡La cafetera está lista para funcionar!");
}
public void destroy() {
System.out.println("La cafetera se apaga...");
}
}
Al inicializar el bean, Spring llamará al método init, y al terminar la aplicación llamará al método destroy.
Implementación de las interfaces InitializingBean y DisposableBean
Si prefieres usar interfaces, Spring ofrece dos opciones:
InitializingBean— para métodos de inicialización.DisposableBean— para métodos de finalización.
Ejemplo:
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class CoffeeMaker implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() {
System.out.println("¡La cafetera está lista para funcionar! (Vía InitializingBean)");
}
@Override
public void destroy() {
System.out.println("La cafetera se apaga... (Vía DisposableBean)");
}
}
La gente de programación suele bromear: "Si tienes una interfaz para todo, ¡es que estás programando en Java!". En Spring pasó algo parecido, pero con la llegada de las anotaciones @PostConstruct y @PreDestroy los desarrolladores empezaron a usar menos las interfaces.
5. Ciclo de vida de Spring Beans en la práctica
Ahora veamos un ejemplo completo usando anotaciones. Crearemos la clase CoffeeMaker con la anotación @Component y configuraremos su ciclo de vida.
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class CoffeeMaker {
@PostConstruct
public void heatUp() {
System.out.println("La cafetera se calienta...");
}
@PreDestroy
public void shutDown() {
System.out.println("La cafetera se apaga...");
}
public void brewCoffee() {
System.out.println("¡Preparando café!");
}
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
CoffeeMaker coffeeMaker = context.getBean(CoffeeMaker.class);
coffeeMaker.brewCoffee();
context.close();
}
}
@Configuration
@ComponentScan("com.example")
class AppConfig {}
Salida en la consola:
La cafetera se calienta...
¡Preparando café!
La cafetera se apaga...
Fíjate que el método heatUp se ejecuta automáticamente tras crear el objeto, y el método shutDown justo antes de destruirlo.
6. Consejos prácticos
- Usa
@PostConstructy@PreDestroycuando puedas. Estas anotaciones son sencillas, claras y están pensadas para trabajar con el ciclo de vida. - Evita lógica compleja en los métodos de inicialización o de cierre. Los métodos anotados deberían usarse para configurar, validar o registrar componentes necesarios.
- Gestiona los recursos. Si tu bean usa recursos externos (por ejemplo, una base de datos o conexiones de red), asegúrate de liberarlos en el método de finalización.
- Prueba el ciclo de vida regularmente. Esto es especialmente importante en aplicaciones con configuraciones complejas.
Cuando entiendes el ciclo de vida de los Spring Beans y cómo gestionar su creación, inicialización y destrucción, empiezas a controlar mucho mejor el comportamiento de tu aplicación. Este conocimiento es útil en todas las etapas del desarrollo, desde pequeñas utilidades hasta el diseño de microservicios escalables.
GO TO FULL VERSION