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.

Architect
Architect
Architect
Why Is Spring Boot So Slow to Start? A Deep Dive into Its Startup Process

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaPerformance OptimizationBackend DevelopmentSpringBootProfilingStartup Performance
Architect
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.