Understanding the SpringApplication Startup Process in Spring Boot
This article explains how Spring Boot launches an application by creating an AnnotationConfigApplicationContext, registering annotation processors, loading the primary source class, and invoking ConfigurationClassPostProcessor during the refresh phase, with detailed code examples illustrating each step.
From SpringApplication Start
Typically a Spring Boot application is started by defining a class with a main method and calling SpringApplication.run :
@SpringBootApplication
public class AutoConfigApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(AutoConfigApplication.class, args);
}
}SpringApplication.run receives two arguments: the primarySource (the class passed in) and the command‑line arguments. Internally it creates an ApplicationContext by invoking the protected createApplicationContext method.
protected ConfigurableApplicationContext createApplicationContext() {
Class
contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
} catch (ClassNotFoundException ex) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}In a non‑web environment the created context is an AnnotationConfigApplicationContext . Its default constructor creates two helper objects:
AnnotatedBeanDefinitionReader – used for manual bean registration.
ClassPathBeanDefinitionScanner – scans for @Component , @Repository , @Service , etc.
Both helpers register a set of annotation processors via AnnotationConfigUtils.registerAnnotationConfigProcessors :
public static Set
registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
// ...
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// ...
return beanDefs;
}After the AnnotationConfigApplicationContext is fully constructed, SpringApplication loads the primarySource (e.g., AutoConfigApplication ) into the context, resulting in an additional BeanDefinition for that class.
Summary of What SpringApplication Does
Creates an AnnotationConfigApplicationContext .
Registers annotation‑processing post‑processors such as ConfigurationClassPostProcessor .
Loads the primarySource (the class passed to run ) into the context.
The most important point is that the context now contains both the user’s primary source bean and the configuration‑class post‑processor.
When Is @Configuration Processed?
After the primary source and post‑processors are in place, the ConfigurationClassPostProcessor (a BeanDefinitionRegistryPostProcessor ) is invoked during the refresh phase of the ApplicationContext :
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ...
invokeBeanFactoryPostProcessors(beanFactory);
// ...
}
}
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List
beanFactoryPostProcessors) {
// Find all BeanDefinitionRegistryPostProcessor beans
String[] postProcessorNames = beanFactory.getBeanNamesForType(
BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
// ... collect and sort ...
}
// Execute them
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// ...
}
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection
postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}The postProcessBeanDefinitionRegistry method of ConfigurationClassPostProcessor parses all @Configuration candidates, sorts them, and loads the resulting bean definitions:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List
configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
// already processed
} else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
if (configCandidates.isEmpty()) {
return;
}
// Sort candidates
configCandidates.sort((bd1, bd2) -> Integer.compare(
ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()),
ConfigurationClassUtils.getOrder(bd2.getBeanDefinition())));
// Parse and load
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// ... parsing loop omitted for brevity ...
this.reader.loadBeanDefinitions(configClasses);
}Although the example class AutoConfigApplication does not declare @Configuration directly, it is treated as a configuration class because @SpringBootApplication is meta‑annotated with @SpringBootConfiguration , which itself includes @Configuration .
Thus, the startup sequence ties together the creation of the application context, registration of essential post‑processors, and the parsing of configuration classes to fully initialise a Spring Boot application.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.