Backend Development 35 min read

Spring Boot Startup Configuration, Extension Points, and Performance Optimization Techniques

This article explains the principles of Spring Boot startup configuration, demonstrates how to intervene using ApplicationContextInitializer, SpringApplicationRunListener, ApplicationRunner, and CommandLineRunner, and provides practical optimization tips such as reducing dependencies, adjusting auto‑configuration, enabling lazy loading, compile‑time optimizations, log level tuning, and caching to speed up application startup.

Top Architect
Top Architect
Top Architect
Spring Boot Startup Configuration, Extension Points, and Performance Optimization Techniques

This article provides a comprehensive guide on Spring Boot startup configuration and various ways to intervene in the boot process.

1. Spring Boot Startup Configuration Principles

The article outlines how Spring Boot loads default configuration properties from application.properties or application.yml and how developers can modify them using annotations such as @ConfigurationProperties and @EnableConfigurationProperties .

2. Startup Process Interventions

Modify default configuration properties.

Load additional configuration files.

Define custom beans using @Component or @SpringBootAnnotation .

Execute initialization logic with ApplicationRunner or CommandLineRunner .

Perform post‑shutdown cleanup.

(1) ApplicationContextInitializer Extension

By implementing ApplicationContextInitializer , developers can customize the ConfigurableApplicationContext before it is refreshed.

package org.zyf.javabasic.springextend.runext;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.support.ResourcePropertySource;
import java.io.IOException;

public class InterveneApplicationContextInitializer implements ApplicationContextInitializer
{
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableEnvironment environment = configurableApplicationContext.getEnvironment();
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            System.out.println("InterveneApplicationContextInitializer initialize :" + configurableApplicationContext);
            environment.getPropertySources().addFirst(new ResourcePropertySource("classpath:zyftest.properties"));
            System.out.println("InterveneApplicationContextInitializer initialize add FirstResourcePropertySource  classpath:zyftest.properties");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

The initializer must be registered in src/main/resources/META-INF/spring.factories :

org.springframework.context.ApplicationContextInitializer=org.zyf.javabasic.springextend.runext.InterveneApplicationContextInitializer

(2) Adding Custom PropertySource

package org.zyf.javabasic.springextend.runext;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.ResourcePropertySource;

public class InterveneApplicationContextInitializer implements ApplicationContextInitializer
{
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        PropertySource
propertySource = new MyPropertySource("myPropertySource");
        environment.getPropertySources().addLast(propertySource);
        System.out.println("InterveneApplicationContextInitializer initialize add PropertySource  myPropertySource");
    }

    private static class MyPropertySource extends PropertySource
{
        private static final String MY_PROPERTY_SOURCE_KEY = "my.property.source.key";
        public MyPropertySource(String name) { super(name); }
        @Override
        public Object getProperty(String name) {
            if (MY_PROPERTY_SOURCE_KEY.equals(name)) {
                return "myPropertySourceValue";
            }
            return null;
        }
    }
}

(3) Registering Custom Bean

package org.zyf.javabasic.springextend.runext;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

public class InterveneApplicationContextInitializer implements ApplicationContextInitializer
{
    @Override
    public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
        ConfigurableListableBeanFactory beanFactory = configurableApplicationContext.getBeanFactory();
        MyBean myBean = new MyBean();
        beanFactory.registerSingleton("myBean", myBean);
        System.out.println("InterveneApplicationContextInitializer initialize registerSingleton  myBean");
    }

    private static class MyBean {
        private String name = "myBean";
        public String getName() { return name; }
    }
}

(4) SpringApplicationRunListener Extension

package org.zyf.javabasic.springextend.runext;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

public class IntervenRunListener implements SpringApplicationRunListener {
    private final SpringApplication application;
    private final String[] args;
    public IntervenRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
    }
    @Override public void starting() { System.out.println("IntervenRunListener starting"); }
    @Override public void environmentPrepared(ConfigurableEnvironment environment) { System.out.println("IntervenRunListener environmentPrepared"); }
    @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("IntervenRunListener contextPrepared"); }
    @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("IntervenRunListener contextLoaded"); }
    @Override public void started(ConfigurableApplicationContext context) { System.out.println("IntervenRunListener started"); }
    @Override public void running(ConfigurableApplicationContext context) { System.out.println("IntervenRunListener running"); }
    @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { System.out.println("IntervenRunListener failed"); }
}

Register it in src/main/resources/META-INF/spring.factories :

org.springframework.boot.SpringApplicationRunListener=org.zyf.javabasic.springextend.runext.IntervenRunListener

(5) ApplicationRunner Extension

package org.zyf.javabasic.springextend.runext;

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class CacheInitiator implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("CacheInitiator cache deal!");
    }
}

(6) CommandLineRunner Extension

package org.zyf.javabasic.springextend.runext;

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class UserImportCommand implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("UserImportCommand readUserFromFile importUsers!");
    }
    private List
readUserFromFile(String fileName) {
        // omitted file reading logic
        return Lists.newArrayList();
    }
}

Performance Optimization Recommendations

1. Reduce Dependencies

Analyze the project's pom.xml or build.gradle and remove unnecessary libraries such as unused starters (e.g., spring-boot-starter-data-jpa , spring-boot-starter-security ) to shorten classpath scanning.

2. Adjust Auto‑Configuration

Exclude unneeded auto‑configuration classes via @SpringBootApplication(exclude = {DataJpaAutoConfiguration.class, SecurityAutoConfiguration.class}) or create custom configuration classes to load only required components.

3. Enable Lazy Loading

Annotate rarely used beans with @Lazy or define lazy beans in configuration methods to defer their initialization until first use.

4. Compile‑Time Optimizations

For Spring Boot 2.4+, add --add-opens arguments in the Maven Compiler plugin to reduce reflection overhead.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <compilerArgs>
            <arg>--add-opens</arg>
            <arg>java.base/java.lang=ALL-UNNAMED</arg>
            <arg>--add-opens</arg>
            <arg>java.base/java.util=ALL-UNNAMED</arg>
        </compilerArgs>
    </configuration>
</plugin>

5. Lower Log Level

Set root logging to WARN in application.properties or application.yml to reduce I/O during startup.

logging.level.root=WARN

6. Use Caching

Enable Spring’s cache abstraction with @EnableCaching and annotate expensive methods with @Cacheable to avoid repeated initialization work.

@EnableCaching
@Service
public class MyService {
    @Cacheable("myCache")
    public MyData getData(String key) { /* fetch from DB */ }
}

By applying these techniques—cleaning dependencies, fine‑tuning auto‑configuration, leveraging lazy loading, enabling compile‑time optimizations, adjusting log levels, and caching—developers can significantly reduce Spring Boot application startup time and improve overall performance.

backendJavaperformancestartup optimizationSpring Boot
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.