Skip to content

Autoconfiguración de Spring Boot

Entiende cómo funciona la autoconfiguración de Spring Boot bajo el capó con ejemplos prácticos de configuración de Tomcat embebido y beans condicionales.

Spring Boot ha ganado mucha popularidad desde que fue lanzado por primera vez por Pivotal (ahora parte de VMware). Como se describe en su sitio web, facilita la creación de aplicaciones basadas en Spring independientes y de grado de producción que puedes “simplemente ejecutar”. También intenta ser opinionado para reducir el boilerplate de configuración. Pero, ¿te has preguntado cómo logra Spring Boot eso? ¿Cómo configura tu aplicación automágicamente?

En este post, intentaré explicar el mecanismo de autoconfiguración enfocándome en la parte del servidor web embebido, que es una de las más interesantes. Al pasar por este ejemplo, entenderás cómo funciona la autoconfiguración y qué condiciones se usan para incluir (o no) una característica específica en tu aplicación.

Spring Initializr mostrando opciones de autoconfiguración
Spring Initializr con diferentes dependencias starter que activan la autoconfiguración

Cómo funciona la autoconfiguración de Spring Boot

La lógica de autoconfiguración en Spring Boot está implementada usando algunas anotaciones @Conditional* de Spring, introducidas en Spring 4. Estas anotaciones permiten a Spring incluir (o no) beans en el Application Context dependiendo de la presencia de otros beans, clases en el classpath, propiedades de configuración, etc.

Al combinar estas condiciones con los JARs presentes en tu classpath, Spring Boot puede hacer una suposición bastante buena sobre qué funcionalidad necesita tu aplicación y configurar el Application Context en consecuencia.

Veamos cómo funciona esto explicando cómo se configura el servidor Tomcat embebido.

La configuración de Tomcat embebido

Cuando incluyes spring-boot-starter-web en tu proyecto, Spring Boot configurará automáticamente un servidor Tomcat embebido para ti. Pero ¿cómo sucede esta magia?

Sigamos la cadena de dependencias:

1. Dependencias Starter

Cuando agregas spring-boot-starter-web a tu proyecto, trae varias dependencias transitivas:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

Este starter incluye:

  • spring-boot-starter-tomcat (Tomcat embebido)
  • spring-webmvc (Spring MVC)
  • Otras dependencias relacionadas con web

2. Clases de autoconfiguración

La anotación @EnableAutoConfiguration (incluida en @SpringBootApplication) activa Spring Boot para buscar clases de autoconfiguración en el classpath.

Una de estas clases es ServletWebServerFactoryAutoConfiguration:

@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
         ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
         ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
         ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
    // Configuration logic here
}

3. Configuración condicional

Nota la anotación @ConditionalOnClass(ServletRequest.class). Esto significa que esta configuración solo se activará si ServletRequest.class está presente en el classpath.

La anotación @Import trae configuraciones específicas para diferentes servidores embebidos. Veamos la de Tomcat:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class,
                         search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {

    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(
            ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
            ObjectProvider<TomcatContextCustomizer> contextCustomizers,
            ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.getTomcatConnectorCustomizers()
               .addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
        factory.getTomcatContextCustomizers()
               .addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
        factory.getTomcatProtocolHandlerCustomizers()
               .addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
        return factory;
    }
}

4. Las condiciones explicadas

La configuración EmbeddedTomcat tiene varias condiciones:

  • @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }): Esta configuración solo se activa si todas estas clases están presentes en el classpath.
  • @ConditionalOnMissingBean(value = ServletWebServerFactory.class): Este bean solo se crea si no existe ya un bean ServletWebServerFactory en el contexto de aplicación.

5. Cadena de dependencias

La presencia de estas clases en el classpath viene de la cadena de dependencias:

spring-boot-starter-web
└── spring-boot-starter-tomcat
    └── tomcat-embed-core
        └── Contiene Tomcat.class, UpgradeProtocol.class, etc.

Probar la autoconfiguración

Puedes ver qué autoconfiguraciones se están aplicando a tu aplicación agregando esto a tu application.properties:

logging.level.org.springframework.boot.autoconfigure=DEBUG
debug=true

Cuando ejecutes tu aplicación, verás una salida como:

============================
CONDITIONS EVALUATION REPORT
============================

Positive matches:
-----------------
ServletWebServerFactoryAutoConfiguration matched:
  - @ConditionalOnClass found required class 'javax.servlet.ServletRequest'
  - found 'session' scope

ServletWebServerFactoryConfiguration.EmbeddedTomcat matched:
  - @ConditionalOnClass found required classes 'javax.servlet.Servlet',
    'org.apache.catalina.startup.Tomcat', 'org.apache.coyote.UpgradeProtocol'
  - @ConditionalOnMissingBean (types: org.springframework.boot.web.servlet.server.ServletWebServerFactory;
    SearchStrategy: CURRENT) did not find any beans

Negative matches:
-----------------
ServletWebServerFactoryConfiguration.EmbeddedJetty:
  Did not match:
    - @ConditionalOnClass did not find required class 'org.eclipse.jetty.server.Server'

ServletWebServerFactoryConfiguration.EmbeddedUndertow:
  Did not match:
    - @ConditionalOnClass did not find required class 'io.undertow.Undertow'

Escenarios comunes de autoconfiguración

Cambiar servidores embebidos

Si quieres usar Jetty en lugar de Tomcat, puedes:

  1. Excluir Tomcat del starter:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
  1. Agregar el starter de Jetty:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Ahora las condiciones @ConditionalOnClass coincidirán con Jetty en lugar de Tomcat, y Spring Boot configurará Jetty automáticamente.

Configuración personalizada del servidor

También puedes proporcionar tu propio bean ServletWebServerFactory para personalizar la configuración del servidor:

@Bean
public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.setPort(9000);
    factory.setSessionTimeout(10, TimeUnit.MINUTES);
    return factory;
}

Dado que ahora hay un bean ServletWebServerFactory en el contexto, la condición @ConditionalOnMissingBean en la autoconfiguración evitará que se cree el predeterminado.

Anotaciones clave de autoconfiguración

Aquí están las anotaciones condicionales más comunes usadas en la autoconfiguración de Spring Boot:

  • @ConditionalOnClass: La configuración se incluye solo si las clases especificadas están presentes en el classpath
  • @ConditionalOnMissingClass: La configuración se incluye solo si las clases especificadas NO están presentes
  • @ConditionalOnBean: La configuración se incluye solo si el bean especificado está presente en el contexto
  • @ConditionalOnMissingBean: La configuración se incluye solo si el bean especificado NO está presente en el contexto
  • @ConditionalOnProperty: La configuración se incluye basándose en la presencia/valor de propiedades de configuración
  • @ConditionalOnWebApplication: La configuración se incluye solo en aplicaciones web
  • @ConditionalOnNotWebApplication: La configuración se incluye solo en aplicaciones no web

Crear autoconfiguración personalizada

Puedes crear tu propia autoconfiguración:

  1. Creando una clase de configuración con anotaciones condicionales
  2. Agregándola al archivo META-INF/spring.factories en tu JAR
  3. Incluyendo el JAR en el classpath de tu proyecto

Ejemplo spring.factories:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyCustomAutoConfiguration

Entender la magia

La “magia” de la autoconfiguración de Spring Boot se reduce a:

  1. Valores predeterminados opinionados: Spring Boot hace suposiciones razonables sobre lo que necesitas basándose en tus dependencias
  2. Configuración condicional: Usando anotaciones @Conditional* para incluir/excluir configuraciones basadas en classpath y contexto
  3. Dependencias Starter: Conjuntos de dependencias cuidadosamente elaborados que traen las clases correctas para activar la autoconfiguración
  4. Capacidad de sobrescritura: Siempre puedes sobrescribir los valores predeterminados proporcionando tus propios beans

El ejemplo de Tomcat embebido muestra cómo todas estas piezas trabajan juntas:

  • El spring-boot-starter-web trae las clases de Tomcat
  • La presencia de estas clases activa la autoconfiguración de Tomcat
  • Si proporcionas tu propio bean de factory del servidor, la autoconfiguración se retira

Conclusión

La autoconfiguración de Spring Boot no es magia—es un uso inteligente de las características de configuración condicional de Spring combinadas con dependencias starter bien diseñadas. Al entender cómo funcionan @ConditionalOnClass, @ConditionalOnMissingBean, y otras anotaciones condicionales, puedes entender mejor qué está haciendo Spring Boot por ti y cómo personalizarlo cuando sea necesario.

El ejemplo del servidor embebido demuestra los principios clave:

  • Las dependencias traen clases que activan la autoconfiguración
  • Las anotaciones condicionales determinan cuándo deben aplicarse las configuraciones
  • Siempre puedes sobrescribir los valores predeterminados proporcionando tus propios beans
  • La salida de debug te ayuda a entender qué configuraciones se están aplicando

Esta comprensión te ayudará a depurar problemas, personalizar configuraciones, e incluso crear tus propias autoconfiguraciones cuando construyas bibliotecas reutilizables o frameworks internos.

Master Microservices with Spring Boot

A hands-on guide to building production-ready microservices

Get the Book

Get More Architecture Insights

Join hundreds of software architects and engineers getting practical insights delivered to their inbox.

Volver al Blog