Gestión del Ciclo de Vida y Configuración de Beans en Spring

Gestión del Ciclo de Vida y Configuración de Beans en Spring

El contenedor de Spring implementa los principios de Inversión de Control (IoC) y Desacoplamiento mediante Inyección de Dependencias (DI). Estos mecanismos trasladan la responsabilidad de crear y administrar objetos (componentes) de la aplicación al framework. Los objetos gestionados por el contenedor de Spring se denominan Beans. Un Bean es una instancia de Java que se registra en el contenedor de Spring y cuyo ciclo de vida, configuración y dependencias son administrados por este.

Contenedores IoC en Spring

El contenedor de Spring es el núcleo que administra los Beans. Las interfaces principales para interactuar con el contenedor son:

  • BeanFactory: Interfaz raíz que proporciona la funcionalidad básica de contenedor IoC.
  • ApplicationContext: Interfaz que hereda de BeanFactory y añade características más ricas como la internacionalización, acceso a recursos y la publicación de eventos. Es la interfaz más utilizada en aplicaciones reales.

Una diferencia clave es la estrategia de inicialización: BeanFactory inicializa Beans de forma perezosa (al momento de la primera solicitud), mientras que ApplicationContext pre-inicializa los Beans de ámbito singleton al arrancar el contenedor, lo que puede mejorar el rendimiento.

Configuración de Beans mediante XML

La configuración clásica de Spring utiliza archivos XML. La raíz es el elemento <beans>, y cada Bean se define con un elemento <bean> que especifica, como mínimo, un id único y la clase class.

Configuración del Ámbito (Scope): Por defecto, un Bean es singleton (una única instancia en el contenedor). Se puede cambiar a prototype (una nueva instancia por cada solicitud).

<bean id="servicioPrimario" class="com.ejemplo.ServicioPrimario" scope="singleton"/>
<bean id="servicioPrototype" class="com.ejemplo.ServicioPrototype" scope="prototype"/>

</div>Instanciación de Beans
----------------------

### 1. Mediante Constructor (por defecto)

Spring utiliza por defecto el constructor sin argumentos de la clase del Bean.

<div class="code-block"> ```

    public class MiComponente {
        public MiComponente() {
            System.out.println("Constructor ejecutado");
        }
    }
    
<bean id="miComponente" class="com.ejemplo.MiComponente"/>

</div>### 2. Mediante Fábrica Estática

Se invoca un método estático de una fábrica para obtener la instancia del Bean. El atributo `class` apunta a la fábrica, y `factory-method` al nombre del método.

<div class="code-block"> ```

    public class FabricaComponenteA {
        public static ComponenteA crear() {
            // Lógica compleja o acceso a API externa (ej. MyBatis Mapper)
            return new ComponenteA();
        }
    }
    
<bean id="componenteA" class="com.ejemplo.FabricaComponenteA" factory-method="crear"/>

</div>### 3. Mediante Fábrica de Instancia

Se invoca un método no estático de una instancia (Bean) ya creada.

<div class="code-block"> ```

    public class FabricaComponenteB {
        public ComponenteB producir() {
            return new ComponenteB();
        }
    }
    
<!-- 1. Definir el Bean de la fábrica -->
<bean id="fabricaB" class="com.ejemplo.FabricaComponenteB"/>
<!-- 2. Definir el Bean objetivo usando la fábrica -->
<bean id="componenteB" factory-bean="fabricaB" factory-method="producir"/>

</div>Spring también ofrece una interfaz `FactoryBean` para simplificar este proceso, donde la fábrica misma es el Bean definido.

Ensamblaje (Wiring) e Inyección de Dependencias
-----------------------------------------------

### Ensamblaje mediante XML

Existen dos formas principales de inyectar dependencias en los Beans configurados en XML:

1. **Inyección por Setter:** Requiere que la clase tenga un constructor sin argumentos y métodos setter para las propiedades.
2. **Inyección por Constructor:** Las dependencias se pasan como argumentos del cosntructor.

Spring determina la estrategia de ensamblado automático (*autowiring*) a través del atributo `autowire` en el elemento `<bean>` (por nombre, por tipo, etc.).

### Ensamblaje mediante Anotaciones (Recomendado)

Las anotaciones simplifican enormemente la configuración. Es necesario habilitar el escaneo de componentes en el XML.

<div class="code-block"> ```

    <context:component-scan base-package="com.ejemplo"/>
    
Anotación Propósito
@Component Marcar una clase como un Bean genérico.
@Service, @Repository, @Controller Especializaciones de @Component con semántica más clara (capa de servicio, persistencia, presentación).
@Autowired Inyección automática de dependencias (por tipo).
@Resource Inyección por nombre (JSR-250).
@Value Inyección de valores literales o desde propiedades.
@Scope Definir el ámbito del Bean.

Ciclo de Vida de un Bean

Spring administra el ciclo de vida completo de los Beans singleton, pero solo la creación de los Beans prototype. Las fases son:

1. Creación

  • singleton: Se crea al iniciar el contenedor (o de forma perezosa con lazy-init="true").
  • prototype: Se crea en cada petición (context.getBean()).

2. Inicialización

Se ejecuta después de que las dependencias hayan sido inyectadas. Se puede definir de tres maneras:

  1. Enterfaz InitializingBean: Implementar el método afterPropertiesSet().
  2. Método personalizado en XML: Usar el atributo init-method.
  3. Anotación @PostConstruct: (JSR-250) Método estándar de Java.

3. Destrucción

Se ejecuta antes de que el contenedor destruya el Bean (solo para singleton). Formas de definirlo:

  1. Interfaz DisposableBean: Implementar el método destroy().
  2. Método personalizado en XML: Usar el atributo destroy-method.
  3. Anotación @PreDestroy: (JSR-250) Método estándar de Java.

Ejemplo completo con anotaciones:

@Component
@Scope("singleton")
public class MotorServicio {

    public MotorServicio() {
        System.out.println("1. Constructor: MotorServicio creado");
    }

    @Autowired
    private RepositorioDatos repositorio; // Inyección automática

    @Value("${app.nombre}")
    private String nombreApp;

    @PostConstruct
    public void inicializar() {
        System.out.println("2. Inicialización: Motor arrancado. App: " + nombreApp);
        repositorio.conectar();
    }

    public String procesar() {
        return repositorio.obtenerDatos();
    }

    @PreDestroy
    public void detener() {
        System.out.println("3. Destrucción: Liberando recursos del motor");
        repositorio.desconectar();
    }
}

</div><div class="code-block"> ```

    // Prueba del ciclo de vida
    public class PruebaCicloVida {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
            MotorServicio motor = ctx.getBean(MotorServicio.class);
            motor.procesar();
            ctx.close(); // Dispara el método @PreDestroy
        }
    }
    

Etiquetas: Spring IOC ApplicationContext BeanFactory dependency injection

Publicado el 6-19 20:57