Introducción a Spring Framework
Spring es un framework de código abierto y ligero para el desarrollo en Java, diseñado para simplificar la creación de aplicaciones empresariales. Su arquitectura modular permite a los desarrolladores seleccionar los componentes necesarios. Los pilares fundamentales de Spring son la Inversión de Control (IoC) y la Programación Orientada a Aspectos (AOP).
- IoC (Inversión de Control): También conocida como Inyección de Dependencias (DI). En lugar de que las clases creen manualmente sus dependencias (objetos), el contenedor de Spring se encarga de crearlas e inyectarlas según la configuración.
- AOP (Programación Orientada a Aspectos): Facilita la modularización de preocupaciones transversales como la gestión de transacciones, la seguridad o el registro de logs.
Ejemplo inicial sin Spring
Consideremos un ejemplo simple para demostrar el concepto. Primero, una clase básica:
package demo;
public class Saludador {
private String nombre;
public void saludar() {
System.out.println("¡Hola, " + nombre + "!");
}
// Getters y Setters
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
}
Para usar esta clase, un cliente típico crearía la instancia y configuraría sus propiedades manualmente:
package demo;
public class Demostracion {
public static void main(String[] args) {
Saludador obj = new Saludador();
obj.setNombre("Spring Framework");
obj.saludar();
}
}
Implementación con el contenedor IoC de Spring
Spring proporciona un contenedor que administra el ciclo de vida y las dependencias de los objetos (beans). A continuación, se muestra cómo lograr el mismo resultado utilizando Spring.
1. Configuración en XML
Se define un archivo de configuración XML (contexto.xml) que descirbe el bean y sus propiedades:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="miSaludador" class="demo.Saludador">
<property name="nombre" value="Spring IoC"/>
</bean>
</beans>
El cliente ahora solicita el bean al contenedor:
package demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demostracion {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("contexto.xml");
Saludador saludo = (Saludador) ctx.getBean("miSaludador");
saludo.saludar();
}
}
La salida es ¡Hola, Spring IoC!. La clase Saludador permanece inalterada; la creación y configuración del objeto está externalizada en el archivo XML.
Formas de configurar beans en el contenedor
A. Configuración mediante XML (Inyección de Dependencias)
Cuando un bean depende de otro, se puede inyectar la dependencia mediante el constructor o un setter.
Supongamos estas clases:
public class Boligrafo {
private String color;
// Getters y setters...
}
public class Escritor {
private Boligrafo instrumento;
// Inyección por constructor
public Escritor(Boligrafo boligrafo) {
this.instrumento = boligrafo;
}
// Inyección por setter
public void setInstrumento(Boligrafo instrumento) {
this.instrumento = instrumento;
}
public void escribir() {
System.out.println("Escribiendo con bolígrafo de color " + instrumento.getColor());
}
}
Inyección por constructor en XML:
<bean id="miBoligrafo" class="demo.Boligrafo">
<property name="color" value="azul"/>
</bean>
<bean id="escritor1" class="demo.Escritor">
<constructor-arg ref="miBoligrafo"/>
</bean>
Inyección por setter en XML:
<bean id="escritor2" class="demo.Escritor">
<property name="instrumento" ref="miBoligrafo"/>
</bean>
B. Configuración mediante anotaciones (Auto-detección)
Spring puede detectar automáticamente clases anotadsa para registrarlas como beans.
import org.springframework.stereotype.Component;
@Component // Marca la clase como un bean gestionado por Spring
public class Boligrafo {
private String color = "negro";
// Getters...
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Escritor {
private final Boligrafo instrumento;
// Inyección por constructor (implícita con un solo constructor)
@Autowired
public Escritor(Boligrafo boligrafo) {
this.instrumento = boligrafo;
}
public void escribir() {
System.out.println("Usando bolígrafo " + instrumento.getColor());
}
}
Se necesita una clase de configuración que active el escaneo de componentes:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "demo") // Escanea el paquete 'demo'
public class ConfiguracionApp {
}
El contexto se carga con la configuración de anotaciones:
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfiguracionApp.class);
Escritor escritor = ctx.getBean(Escritor.class);
escritor.escribir();
C. Configuración mediante clases Java (@Bean)
Se pueden definir beans directamente en una clase de configuración Java usando el método anotado con @Bean.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ConfiguracionManual {
@Bean
public Boligrafo boligrafoRojo() {
Boligrafo b = new Boligrafo();
b.setColor("rojo");
return b;
}
@Bean
public Escritor escritorConBoligrafoRojo() {
// Inyección por constructor, usando el bean 'boligrafoRojo'
return new Escritor(boligrafoRojo());
}
}
El nombre del método anotado con @Bean se convierte en el identificador (id) del bean. Esto proporciona un control total sobre la lógica de creación.