Why Is Spring Boot So Slow to Start? A Deep Dive into Its Startup Process
This article analyses why Spring Boot startup can take dozens of seconds, breaks down the most time‑consuming phases such as prepareEnvironment and refreshContext, shows profiling code and screenshots, compares a simple MVC demo with a real‑world project, and identifies external client connections and configuration loading as the biggest bottlenecks.
Overview
Spring Boot startup time is dominated by two phases: prepareEnvironment and refreshContext . The author measured a minimal MVC project and a production‑level project (≈100k lines) to identify the main cost drivers.
Bootstrapping Sequence
public void run(String... args) {
listeners.starting(); // 3. start event
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 4. load config, profiles, etc.
context = createApplicationContext(); // 7. create context
prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 8. register initializers, load sources
refreshContext(context); // 9. refresh context (bean creation)
listeners.started(context); // 13. context started event
callRunners(context, applicationArguments); // 14. ApplicationRunner / CommandLineRunner
listeners.running(context); // 15. running event
}prepareEnvironment
This step builds a ConfigurableEnvironment in memory, loads property sources, binds profiles, and publishes ApplicationEnvironmentPreparedEvent. When no remote configuration is used the overhead is negligible.
// simplified logic
ConfigurableEnvironment env = getOrCreateEnvironment();
configureEnvironment(env, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(env);
listeners.environmentPrepared(env);
bindToSpringApplication(env);
return env;refreshContext
The refreshContext phase performs the full bean lifecycle. The most time‑consuming sub‑steps are:
BeanFactory post‑processors (heavy use of Spring’s bean management).
Web container initialization (e.g., embedded Tomcat).
Singleton bean instantiation (core doGetBean / populateBean logic).
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();Production‑Level Findings
A real project (≈35 s startup) showed the following recurring cost sources:
Multiple Container Creation
Both SpringApplication.run() and Cloud bootstrap create separate application contexts, causing the environment to be prepared multiple times.
Configuration Listeners
Listeners such as ConfigFileApplicationListener, BootstrapApplicationListener, and SpringBootServletInitializer load external configuration files and trigger additional bootstrap processing.
Repeated Bean Refreshes
Frequent calls to refresh() (e.g., >40 times in a 100 k‑line project) repeat the entire bean‑creation pipeline, invoking listeners, post‑processors, and Aware callbacks each time.
Massive Bean Loading
A large number of beans pushes most of the time into prepareRefresh and singleton initialization.
Third‑Party Client Creation
Instantiating clients for services such as Redis or MySQL (including connection pools) adds noticeable latency.
Instrumentation Used for Measurement
The author created a lightweight StopWatchExpand utility that records timestamps for arbitrary logical steps and prints a formatted table.
package com.gang.start;
public class StopWatchExpand {
private static List<TaskEntry> taskEntries = new ArrayList<>();
public static String start(String processLine, String node) { /* record start */ }
public static void stop() { /* print table and clear */ }
// internal helpers: logStatistics(), formatTimestamp(), padString(), padChineseNode()
// TaskEntry stores processLine, node, callerClass, callerMethod, timeMillis
}Conclusion
Profiling indicates that the dominant contributors to long Spring Boot startup times are:
External client connections (e.g., Redis, MySQL) that establish network connections or pools.
Configuration loading performed by environment listeners.
The bean‑creation pipeline in refreshContext, especially BeanFactory post‑processors and singleton initialization.
Future work will compare newer Spring Boot versions and alternative lightweight frameworks to see how they mitigate these costs.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
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.
