Backend Development 18 min read

How to Cut Spring Boot Startup Time from 7 Minutes to 40 Seconds

This article explains why a SpringBoot service took 6‑7 minutes to start, shows how to pinpoint the bottlenecks using SpringApplicationRunListener and BeanPostProcessor, and presents concrete optimizations—reducing scan paths, manually registering beans, and fixing cache auto‑configuration—to shrink the local startup time to about 40 seconds.

macrozheng
macrozheng
macrozheng
How to Cut Spring Boot Startup Time from 7 Minutes to 40 Seconds

Background

During daily development a SpringBoot project took 6‑7 minutes to expose its port. By debugging

SpringApplicationRunListener

and

BeanPostProcessor

it was discovered that the bean‑scanning and bean‑injection phases caused the major slowdown.

The following knowledge points are covered:

Observing the SpringBoot

run

method via

SpringApplicationRunListener

;

Monitoring bean‑injection time with

BeanPostProcessor

;

SpringBoot cache auto‑configuration principles;

Starter‑based auto‑configuration and custom starter creation.

Investigating Startup Time

Two main investigation directions were identified:

Trace the SpringBoot service startup process;

Trace bean‑initialization time.

Observing the SpringBoot run Method

The project uses an internal micro‑service component

XxBoot

whose startup flow mirrors SpringBoot: constructing an

ApplicationContext

and then invoking its

run

method.

<code>public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }</code>

The

run

method is divided into several stages defined by the

SpringApplicationRunListener

interface:

<code>public interface SpringApplicationRunListener { void starting(); void environmentPrepared(ConfigurableEnvironment env); void contextPrepared(ConfigurableApplicationContext ctx); void contextLoaded(ConfigurableApplicationContext ctx); void started(ConfigurableApplicationContext ctx); void running(ConfigurableApplicationContext ctx); void failed(ConfigurableApplicationContext ctx, Throwable ex); }</code>

SpringBoot provides a single default implementation

EventPublishingRunListener

that publishes events at each stage. By adding a custom implementation of

SpringApplicationRunListener

and registering it in

META-INF/spring.factories

, timestamps can be logged at the end of each stage to locate the most time‑consuming phases.

Monitoring Bean Initialization Time

The

BeanPostProcessor

interface allows hooking before and after bean initialization. By recording the start time in

postProcessBeforeInitialization

and computing the elapsed time in

postProcessAfterInitialization

, the initialization cost of each bean can be measured.

<code>@Component public class TimeCostBeanPostProcessor implements BeanPostProcessor { private Map<String, Long> costMap = new ConcurrentHashMap<>(); @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { costMap.put(beanName, System.currentTimeMillis()); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { Long start = costMap.get(beanName); if (start != null) { long cost = System.currentTimeMillis() - start; if (cost > 0) { costMap.put(beanName, cost); System.out.println("bean: " + beanName + "\ttime: " + cost); } } return bean; } }</code>

Running this processor revealed a bean that took 43 seconds because it queried a large amount of configuration data from the database and wrote it to Redis.

Optimization Strategies

How to Reduce Excessive Scan Paths

Instead of scanning large third‑party packages, explicitly register only the required beans via JavaConfig. For example, replace the scan of

com.xxx.ad.upm

with a configuration class that defines the needed

UpmResourceClient

bean:

<code>@Configuration public class ThirdPartyBeanConfig { @Bean public UpmResourceClient upmResourceClient() { return new UpmResourceClient(); } }</code>

This eliminates unrelated beans (services, controllers) from the application context, reduces memory usage, and shortens startup time.

How to Address Slow Bean Initialization

For beans that perform heavy work during initialization, consider asynchronous execution or lazy loading. In the example, the slow bean that loads configuration data could be refactored to load data in a background thread after the application has started.

Understanding SpringBoot Cache Auto‑Configuration

SpringBoot’s

@EnableAutoConfiguration

imports a series of auto‑configuration classes listed in

META-INF/spring.factories

. The cache subsystem is configured by

CacheAutoConfiguration

, which imports

CacheConfigurationImportSelector

. This selector chooses one concrete cache configuration based on the available dependencies; in the project it selects

RedisCacheConfiguration

, which creates a

RedisCacheManager

.

If a custom cache component’s package is removed from the scan, SpringBoot still creates its own

RedisCacheManager

because the auto‑configuration class is annotated with

@ConditionalOnMissingBean(CacheManager.class)

. Therefore the missing custom bean is silently replaced by the default one.

Using a Starter for the Cache Component

To make the custom cache component “plug‑and‑play”, add a

META-INF/spring.factories

entry under

org.springframework.boot.autoconfigure.EnableAutoConfiguration

that points to the component’s configuration class (e.g.,

com.xxx.ad.rediscache.XxxAdCacheConfiguration

). This lets SpringBoot import the custom configuration automatically without scanning the whole package.

Result

After applying the above optimizations the local startup time dropped from roughly 7 minutes to about 40 seconds, a dramatic improvement.

CacheSpringBootAuto‑ConfigurationStartup PerformanceBeanPostProcessorJavaConfigbean scanning
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login 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.