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;
}