Inicialización de SpringApplication en Spring Boot: Análisis de la Configuración Inicial

El proceso de inicialización de SpringApplication es fundamantal en la ejecución de aplicaciones Spring Boot. Este artículo explora la configuración inicial sin referencias externas ni contenido promocional.

@SpringBootApplication
public class AppInitializer {
    public static void main(String[] arguments) {
        SpringApplication.run(AppInitializer.class, arguments);
    }
}

Al llamar a SpringApplication.run, se invoca el constructor principal que prepara el contexto de aplicación. El método clave es:

public SpringApplication(Class<?>... startupClasses) {
    this(null, startupClasses);
}

public SpringApplication(ResourceLoader loader, Class<?>... startupClasses) {
    this.resourceLoader = loader;
    Assert.notNull(startupClasses, "Clase principal no puede ser nula");
    this.startupClasses = new LinkedHashSet<>(Arrays.asList(startupClasses));
    this.applicationType = determineApplicationType();
    this.bootstrappers = loadFactories(Bootstrapper.class);
    this.initializers = loadFactories(ApplicationContextInitializer.class);
    this.listeners = loadFactories(ApplicationListener.class);
    this.mainClass = findMainClass();
}

Detección del tipo de aplicación web

El método determineApplicationType() identifica el entorno de ejecución mediante la presencia de clases específicas:

private WebApplicationType determineApplicationType() {
    if (classExists("org.springframework.web.reactive.DispatcherHandler") 
        && !classExists("org.springframework.web.servlet.DispatcherServlet")) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : new String[] {
        "javax.servlet.Servlet", 
        "org.springframework.web.context.ConfigurableWebApplicationContext"
    }) {
        if (!classExists(className)) return WebApplicationType.NONE;
    }
    return WebApplicationType.SERVLET;
}

Carga de componentes mediante Spring Factories

La carga de inicializadores y escuchadores se realiza mediante el mecanismo de Spring Factories:

private <T> List<T> loadFactories(Class<T> factoryInterface) {
    List<T> instances = new ArrayList<>();
    ClassLoader classLoader = getClassLoader();
    try {
        Enumeration<URL> resources = classLoader.getResources("META-INF/spring.factories");
        while (resources.hasMoreElements()) {
            Properties properties = PropertiesLoaderUtils.loadProperties(
                new UrlResource(resources.nextElement())
            );
            String factoryClass = properties.getProperty(factoryInterface.getName());
            if (factoryClass != null) {
                for (String className : factoryClass.split(",")) {
                    instances.add(createInstance(className, factoryInterface));
                }
            }
        }
    } catch (IOException e) {
        throw new IllegalStateException("Error cargando factores", e);
    }
    return Collections.unmodifiableList(instances);
}

Determinación de la clase principal

El método findMainClass() identifica la clase de inicio mediante el stack trace:

private Class<?> findMainClass() {
    try {
        for (StackTraceElement element : new RuntimeException().getStackTrace()) {
            if ("main".equals(element.getMethodName())) {
                return Class.forName(element.getClassName());
            }
        }
    } catch (ClassNotFoundException e) {
        // Ignorar y continuar
    }
    return null;
}

Etiquetas: spring-boot ApplicationContext spring-factories web-application-type

Publicado el 9-18 16:54