5. Spring Boot en Profundidad
⚡ 5.1 Auto-configuración
Section titled “⚡ 5.1 Auto-configuración”¿Qué es la auto-configuración?
Section titled “¿Qué es la auto-configuración?”Spring Boot configura automáticamente tu aplicación basándose en las dependencias que agregas. No necesitas escribir configuración manual.
// Sin Spring Boot (configuración manual)@Configurationpublic class DataSourceConfig { @Bean public DataSource dataSource() { HikariDataSource ds = new HikariDataSource(); ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb"); ds.setUsername("root"); ds.setPassword("password"); ds.setDriverClassName("com.mysql.cj.jdbc.Driver"); return ds; }}
// Con Spring Boot (auto-configuración)// Solo agrega la dependencia y las properties// ¡Spring Boot configura todo automáticamente!Cómo funciona
Section titled “Cómo funciona”// @SpringBootApplication incluye:@SpringBootApplicationpublic class MiApp { }
// Equivale a:@Configuration // Clase de configuración@EnableAutoConfiguration // Habilita auto-configuración@ComponentScan // Escanea componentespublic class MiApp { }Ver auto-configuraciones activas
Section titled “Ver auto-configuraciones activas”# application.propertiesdebug=true
# En consola verás:# ============================# CONDITIONS EVALUATION REPORT# ============================# Positive matches:# DataSourceAutoConfiguration matched# JpaRepositoriesAutoConfiguration matched# Negative matches:# MongoAutoConfiguration did not match📦 5.2 Starter Dependencies
Section titled “📦 5.2 Starter Dependencies”¿Qué son los Starters?
Section titled “¿Qué son los Starters?”Los starters son dependencias que agrupan todo lo necesario para una funcionalidad específica.
Starters más comunes
Section titled “Starters más comunes”| Starter | Incluye |
|---|---|
spring-boot-starter-web | Spring MVC, Tomcat, Jackson |
spring-boot-starter-data-jpa | Spring Data JPA, Hibernate |
spring-boot-starter-security | Spring Security |
spring-boot-starter-test | JUnit, Mockito, AssertJ |
spring-boot-starter-validation | Bean Validation, Hibernate Validator |
spring-boot-starter-actuator | Endpoints de monitoreo |
Ejemplo en pom.xml
Section titled “Ejemplo en pom.xml”<dependencies> <!-- Web: incluye Tomcat, Spring MVC, Jackson --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<!-- JPA: incluye Hibernate, Spring Data JPA --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
<!-- No necesitas especificar versiones --> <!-- spring-boot-starter-parent las gestiona --></dependencies>⚙️ 5.3 application.properties vs application.yml
Section titled “⚙️ 5.3 application.properties vs application.yml”application.properties
Section titled “application.properties”# Configuración del servidorserver.port=8080server.servlet.context-path=/api
# Base de datosspring.datasource.url=jdbc:mysql://localhost:3306/mydbspring.datasource.username=rootspring.datasource.password=secretspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA/Hibernatespring.jpa.hibernate.ddl-auto=updatespring.jpa.show-sql=truespring.jpa.properties.hibernate.format_sql=true
# Logginglogging.level.root=INFOlogging.level.com.miapp=DEBUGapplication.yml
Section titled “application.yml”# Misma configuración en YAMLserver:port: 8080servlet: context-path: /api
spring:datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: secret driver-class-name: com.mysql.cj.jdbc.Driverjpa: hibernate: ddl-auto: update show-sql: true properties: hibernate: format_sql: true
logging:level: root: INFO com.miapp: DEBUGComparación
Section titled “Comparación”| Aspecto | .properties | .yml |
|---|---|---|
| Sintaxis | Plana (key=value) | Jerárquica |
| Legibilidad | Menos legible | Más legible |
| Listas | Índices (list[0]=x) | Guiones (- x) |
| Errores | Más tolerante | Sensible a indentación |
🔧 5.4 Configuración Externa
Section titled “🔧 5.4 Configuración Externa”Orden de prioridad (de mayor a menor)
Section titled “Orden de prioridad (de mayor a menor)”- Argumentos de línea de comandos
- Variables de entorno
- application.properties fuera del JAR
- application.properties dentro del JAR
Inyectar valores de configuración
Section titled “Inyectar valores de configuración”# application.propertiesapp.nombre=Mi Aplicaciónapp.version=1.0.0app.max-usuarios=100
# Variables de entorno (sobrescriben properties)# APP_NOMBRE=Producción App@Servicepublic class AppInfoService {
@Value("${app.nombre}") private String nombre;
@Value("${app.version}") private String version;
@Value("${app.max-usuarios:50}") // Valor por defecto: 50 private int maxUsuarios;
public String getInfo() { return nombre + " v" + version; }}Clase de configuración tipada
Section titled “Clase de configuración tipada”@Configuration@ConfigurationProperties(prefix = "app")public class AppProperties {
private String nombre; private String version; private int maxUsuarios;
// Getters y setters public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } // ...}
// Uso@Servicepublic class MiServicio {
private final AppProperties props;
public MiServicio(AppProperties props) { this.props = props; }
public void mostrarInfo() { System.out.println(props.getNombre()); }}🌍 5.5 Manejo de Perfiles (dev, prod)
Section titled “🌍 5.5 Manejo de Perfiles (dev, prod)”Archivos por perfil
Section titled “Archivos por perfil”src/main/resources/├── application.properties # Configuración común├── application-dev.properties # Solo desarrollo├── application-prod.properties # Solo producción└── application-test.properties # Solo testingConfiguración por perfil
Section titled “Configuración por perfil”# application.properties (común)app.nombre=Mi Appspring.profiles.active=dev
# application-dev.propertiesserver.port=8080spring.datasource.url=jdbc:h2:mem:devdblogging.level.root=DEBUG
# application-prod.propertiesserver.port=80spring.datasource.url=jdbc:postgresql://prod:5432/mydblogging.level.root=WARNActivar perfiles
Section titled “Activar perfiles”# En application.propertiesspring.profiles.active=dev
# Por línea de comandosjava -jar app.jar --spring.profiles.active=prod
# Variable de entornoexport SPRING_PROFILES_ACTIVE=prod
# En IDE (IntelliJ)# Run Configuration → Environment variables → SPRING_PROFILES_ACTIVE=dev📝 5.6 Logs en Spring Boot
Section titled “📝 5.6 Logs en Spring Boot”Configuración de logging
Section titled “Configuración de logging”# Nivel de log por paquetelogging.level.root=INFOlogging.level.org.springframework=WARNlogging.level.com.miapp=DEBUGlogging.level.org.hibernate.SQL=DEBUG
# Archivo de loglogging.file.name=logs/app.loglogging.file.max-size=10MBlogging.file.max-history=30
# Patrón de consolalogging.pattern.console=%d{HH:mm:ss} %-5level %logger{36} - %msg%nUso de logs en código
Section titled “Uso de logs en código”import org.slf4j.Logger;import org.slf4j.LoggerFactory;
@Servicepublic class UsuarioService {
// Crear logger para esta clase private static final Logger log = LoggerFactory.getLogger(UsuarioService.class);
public Usuario buscar(Long id) { log.debug("Buscando usuario con ID: {}", id);
Usuario usuario = repository.findById(id).orElse(null);
if (usuario == null) { log.warn("Usuario no encontrado: {}", id); return null; }
log.info("Usuario encontrado: {}", usuario.getNombre()); return usuario; }
public void eliminar(Long id) { try { repository.deleteById(id); log.info("Usuario eliminado: {}", id); } catch (Exception e) { log.error("Error al eliminar usuario {}: {}", id, e.getMessage(), e); } }}Con Lombok
Section titled “Con Lombok”import lombok.extern.slf4j.Slf4j;
@Slf4j // Genera automáticamente: private static final Logger log = ...@Servicepublic class ProductoService {
public void procesar(Producto producto) { log.info("Procesando producto: {}", producto.getNombre()); }}🔥 5.7 DevTools y Hot Reload
Section titled “🔥 5.7 DevTools y Hot Reload”Agregar DevTools
Section titled “Agregar DevTools”<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional></dependency>Características de DevTools
Section titled “Características de DevTools”| Característica | Descripción |
|---|---|
| Restart automático | Reinicia al detectar cambios en clases |
| LiveReload | Recarga el navegador automáticamente |
| Configuración dev | Desactiva caché de templates |
| H2 Console | Habilita consola web de H2 |
Configuración
Section titled “Configuración”# application.propertiesspring.devtools.restart.enabled=truespring.devtools.livereload.enabled=true
# Excluir carpetas del restartspring.devtools.restart.exclude=static/**,public/**
# Trigger file (solo reinicia cuando se modifica este archivo)spring.devtools.restart.trigger-file=.reloadtrigger🚀 5.8 Personalización del Arranque
Section titled “🚀 5.8 Personalización del Arranque”Banner personalizado
Section titled “Banner personalizado”# src/main/resources/banner.txt__ __ _ _| \/ (_) / \ _ __ _ __| |\/| | | / _ \ | '_ \| '_ \| | | | |/ ___ \| |_) | |_) ||_| |_|_/_/ \_\ .__/| .__/ |_| |_|:: Spring Boot :: v${spring-boot.version}:: App Version :: ${app.version}Desactivar banner
Section titled “Desactivar banner”# application.propertiesspring.main.banner-mode=off
# O en código@SpringBootApplicationpublic class MiApp { public static void main(String[] args) { SpringApplication app = new SpringApplication(MiApp.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); }}Eventos de arranque
Section titled “Eventos de arranque”@Componentpublic class AppStartupListener {
@EventListener(ApplicationReadyEvent.class) public void onApplicationReady() { System.out.println("✅ Aplicación lista para recibir requests"); }
@EventListener(ContextRefreshedEvent.class) public void onContextRefreshed() { System.out.println("🔄 Contexto de Spring inicializado"); }}CommandLineRunner
Section titled “CommandLineRunner”@Componentpublic class DataInitializer implements CommandLineRunner {
private final UsuarioRepository repository;
public DataInitializer(UsuarioRepository repository) { this.repository = repository; }
@Override public void run(String... args) throws Exception { // Se ejecuta al iniciar la aplicación if (repository.count() == 0) { repository.save(new Usuario("admin", "admin@example.com")); System.out.println("👤 Usuario admin creado"); } }}
🐝