3. Fundamentos de Spring Core
🔄 3.1 Concepto de IoC (Inversion of Control)
Section titled “🔄 3.1 Concepto de IoC (Inversion of Control)”¿Qué es IoC?
Section titled “¿Qué es IoC?”Inversión de Control (IoC) es un principio de diseño donde el control del flujo del programa se invierte: en lugar de que tu código controle la creación de objetos, el framework se encarga de ello.
Sin IoC (control tradicional)
Section titled “Sin IoC (control tradicional)”// ❌ TÚ controlas la creación de objetospublic class PedidoService {
public void procesarPedido() { // Tú creas las dependencias manualmente UsuarioRepository usuarioRepo = new UsuarioRepositoryImpl(); EmailService emailService = new GmailEmailService(); LogService logService = new FileLogService();
// Usar las dependencias... }}Con IoC (Spring controla)
Section titled “Con IoC (Spring controla)”// ✅ SPRING controla la creación de objetos@Servicepublic class PedidoService {
private final UsuarioRepository usuarioRepo; private final EmailService emailService; private final LogService logService;
// Spring crea e inyecta las dependencias public PedidoService(UsuarioRepository usuarioRepo, EmailService emailService, LogService logService) { this.usuarioRepo = usuarioRepo; this.emailService = emailService; this.logService = logService; }
public void procesarPedido() { // Usar las dependencias ya inyectadas }}Beneficios de IoC
Section titled “Beneficios de IoC”| Beneficio | Descripción |
|---|---|
| Desacoplamiento | Las clases no conocen las implementaciones concretas |
| Testabilidad | Fácil inyectar mocks para testing |
| Flexibilidad | Cambiar implementaciones sin modificar código |
| Mantenibilidad | Código más limpio y organizado |
💉 3.2 Inyección de Dependencias (DI)
Section titled “💉 3.2 Inyección de Dependencias (DI)”¿Qué es DI?
Section titled “¿Qué es DI?”Dependency Injection (DI) es el mecanismo mediante el cual Spring proporciona las dependencias que una clase necesita, en lugar de que la clase las cree por sí misma.
// La dependencia se "inyecta" desde afuera@Servicepublic class ProductoService {
// Spring inyecta automáticamente esta dependencia private final ProductoRepository repository;
public ProductoService(ProductoRepository repository) { this.repository = repository; // ← Inyección }
public List<Producto> listarTodos() { return repository.findAll(); }}🔧 3.3 Tipos de Inyección
Section titled “🔧 3.3 Tipos de Inyección”1. Inyección por Constructor (Recomendada ✅)
Section titled “1. Inyección por Constructor (Recomendada ✅)”@Servicepublic class UsuarioService {
private final UsuarioRepository repository; private final EmailService emailService;
// ✅ Inyección por constructor - LA MEJOR OPCIÓN @Autowired // Opcional en Spring 4.3+ si hay un solo constructor public UsuarioService(UsuarioRepository repository, EmailService emailService) { this.repository = repository; this.emailService = emailService; }}Ventajas:
- Dependencias inmutables (
final) - Obligatorio proporcionar todas las dependencias
- Fácil de testear
- Detecta dependencias circulares en tiempo de compilación
2. Inyección por Setter
Section titled “2. Inyección por Setter”@Servicepublic class NotificacionService {
private EmailService emailService; private SmsService smsService;
// Inyección por setter @Autowired public void setEmailService(EmailService emailService) { this.emailService = emailService; }
@Autowired(required = false) // Dependencia opcional public void setSmsService(SmsService smsService) { this.smsService = smsService; }}Cuándo usar:
- Dependencias opcionales
- Configuración que puede cambiar en runtime
3. Inyección por Campo (No recomendada ⚠️)
Section titled “3. Inyección por Campo (No recomendada ⚠️)”@Servicepublic class ReporteService {
// ⚠️ Inyección por campo - EVITAR @Autowired private ReporteRepository repository;
@Autowired private PdfGenerator pdfGenerator;
// Difícil de testear sin Spring}Comparación de tipos
Section titled “Comparación de tipos”| Tipo | Inmutable | Testeable | Dependencias opcionales |
|---|---|---|---|
| Constructor | ✅ Sí | ✅ Fácil | ❌ No |
| Setter | ❌ No | ⚠️ Medio | ✅ Sí |
| Campo | ❌ No | ❌ Difícil | ✅ Sí |
📦 3.4 Contenedor de Spring
Section titled “📦 3.4 Contenedor de Spring”¿Qué es el contenedor?
Section titled “¿Qué es el contenedor?”El contenedor de Spring (también llamado IoC Container) es el corazón del framework. Se encarga de:
- Crear los objetos (beans)
- Configurar las dependencias
- Gestionar el ciclo de vida
- Inyectar las dependencias donde se necesiten
┌─────────────────────────────────────────────────────────┐│ CONTENEDOR DE SPRING ││ ││ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ │ Bean A │ │ Bean B │ │ Bean C │ ││ │ @Service │ │ @Repo │ │ @Comp │ ││ └────┬─────┘ └────┬─────┘ └────┬─────┘ ││ │ │ │ ││ └─────────────┼─────────────┘ ││ │ ││ INYECCIÓN DE ││ DEPENDENCIAS │└─────────────────────────────────────────────────────────┘🏭 3.5 BeanFactory vs ApplicationContext
Section titled “🏭 3.5 BeanFactory vs ApplicationContext”BeanFactory
Section titled “BeanFactory”// BeanFactory - Contenedor básico// Carga beans de forma LAZY (cuando se solicitan)BeanFactory factory = new XmlBeanFactory( new ClassPathResource("beans.xml"));
// El bean se crea cuando lo solicitasMiServicio servicio = factory.getBean(MiServicio.class);ApplicationContext
Section titled “ApplicationContext”// ApplicationContext - Contenedor avanzado (RECOMENDADO)// Carga beans de forma EAGER (al iniciar)ApplicationContext context = new AnnotationConfigApplicationContext( AppConfig.class);
// El bean ya está creadoMiServicio servicio = context.getBean(MiServicio.class);Diferencias
Section titled “Diferencias”| Característica | BeanFactory | ApplicationContext |
|---|---|---|
| Carga de beans | Lazy | Eager |
| Eventos | ❌ No | ✅ Sí |
| Internacionalización | ❌ No | ✅ Sí |
| Integración AOP | ❌ No | ✅ Sí |
| Uso recomendado | Recursos limitados | Aplicaciones normales |
🔄 3.6 Ciclo de Vida de los Beans
Section titled “🔄 3.6 Ciclo de Vida de los Beans”Fases del ciclo de vida
Section titled “Fases del ciclo de vida”┌─────────────────────────────────────────────────────────┐│ CICLO DE VIDA DE UN BEAN │├─────────────────────────────────────────────────────────┤│ 1. Instanciación → Spring crea el objeto ││ 2. Inyección de DI → Se inyectan dependencias ││ 3. @PostConstruct → Método de inicialización ││ 4. Bean listo → Disponible para uso ││ 5. @PreDestroy → Método de limpieza ││ 6. Destrucción → Spring destruye el bean │└─────────────────────────────────────────────────────────┘Ejemplo práctico
Section titled “Ejemplo práctico”@Servicepublic class ConexionService {
private Connection conexion;
// Constructor - Fase 1 y 2 public ConexionService() { System.out.println("1. Bean instanciado"); }
// Inicialización - Fase 3 @PostConstruct public void inicializar() { System.out.println("2. Inicializando conexión..."); this.conexion = crearConexion(); }
// Uso normal - Fase 4 public void ejecutarQuery(String sql) { // Bean en uso }
// Limpieza - Fase 5 @PreDestroy public void limpiar() { System.out.println("3. Cerrando conexión..."); this.conexion.close(); }}📝 3.7 Configuración XML vs Java
Section titled “📝 3.7 Configuración XML vs Java”Configuración XML (Legacy)
Section titled “Configuración XML (Legacy)”<!-- beans.xml - Configuración tradicional --><?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">
<!-- Definir un bean --> <bean id="usuarioService" class="com.ejemplo.UsuarioService"> <constructor-arg ref="usuarioRepository"/> </bean>
<bean id="usuarioRepository" class="com.ejemplo.UsuarioRepositoryImpl"/>
</beans>Configuración Java (Moderna ✅)
Section titled “Configuración Java (Moderna ✅)”@Configurationpublic class AppConfig {
@Bean public UsuarioRepository usuarioRepository() { return new UsuarioRepositoryImpl(); }
@Bean public UsuarioService usuarioService(UsuarioRepository repository) { return new UsuarioService(repository); }}🏷️ 3.8 Configuración Basada en Anotaciones
Section titled “🏷️ 3.8 Configuración Basada en Anotaciones”Anotaciones principales
Section titled “Anotaciones principales”// @Configuration - Clase de configuración@Configurationpublic class AppConfig {
// @Bean - Define un bean manualmente @Bean public MiServicio miServicio() { return new MiServicio(); }}
// @Component - Bean genérico (detectado por escaneo)@Componentpublic class MiComponente { }
// @Service - Bean de lógica de negocio@Servicepublic class UsuarioService { }
// @Repository - Bean de acceso a datos@Repositorypublic class UsuarioRepository { }
// @Controller - Bean de controlador web@Controllerpublic class UsuarioController { }
// @RestController - Controlador REST (combina @Controller + @ResponseBody)@RestControllerpublic class ApiController { }Escaneo de componentes
Section titled “Escaneo de componentes”// Spring Boot escanea automáticamente desde el paquete base@SpringBootApplication // Incluye @ComponentScanpublic class MiAplicacion { public static void main(String[] args) { SpringApplication.run(MiAplicacion.class, args); }}
// Escaneo manual (si es necesario)@Configuration@ComponentScan(basePackages = "com.ejemplo")public class AppConfig { }Jerarquía de anotaciones
Section titled “Jerarquía de anotaciones” @Component │ ┌──────────────┼──────────────┐ │ │ │ @Service @Repository @Controller │ │ │ @RestController
🐝