Backend Development 32 min read

Spring Boot Startup Configuration Principles, Extension Points, and Performance Optimizations

This article explains the core principles of Spring Boot startup configuration, demonstrates how to intervene using ApplicationContextInitializer, SpringApplicationRunListener, ApplicationRunner, and CommandLineRunner, and provides practical optimization techniques to significantly reduce application launch time.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Spring Boot Startup Configuration Principles, Extension Points, and Performance Optimizations

Spring Boot Startup Configuration Principles

The article begins by outlining the basic mechanism of Spring Boot's auto‑configuration and property loading, emphasizing that understanding these fundamentals is essential before applying any optimization.

Intervention Points During Startup

Several extension points are described:

Modify default configuration properties with @ConfigurationProperties and @EnableConfigurationProperties .

Load additional configuration files (e.g., application.yml ).

Create custom beans using @Component or a custom @SpringBootAnnotation .

Execute initialization logic via ApplicationRunner or CommandLineRunner .

Perform post‑shutdown cleanup.

ApplicationContextInitializer Extension

Implementing ApplicationContextInitializer<ConfigurableApplicationContext> allows modification of the ConfigurableApplicationContext before it is refreshed. Typical tasks include altering the environment, adding custom PropertySource , and registering singleton beans.

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 ctx) {
        ConfigurableEnvironment env = ctx.getEnvironment();
        try {
            ObjectMapper mapper = new ObjectMapper();
            System.out.println("InterveneApplicationContextInitializer initialize :" + ctx);
            env.getPropertySources().addFirst(new ResourcePropertySource("classpath:zyftest.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

To activate the initializer, add the fully qualified class name to src/main/resources/META-INF/spring.factories :

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

Adding a Custom PropertySource

A custom PropertySource can be created and registered:

package org.zyf.javabasic.springextend.runext;

import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.PropertySource;

public class InterveneApplicationContextInitializer implements ApplicationContextInitializer
{
    @Override
    public void initialize(ConfigurableApplicationContext ctx) {
        PropertySource
ps = new MyPropertySource("myPropertySource");
        ctx.getEnvironment().getPropertySources().addLast(ps);
    }

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

Registering a Custom Bean

Beans can be registered programmatically:

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 ctx) {
        ConfigurableListableBeanFactory bf = ctx.getBeanFactory();
        MyBean myBean = new MyBean();
        bf.registerSingleton("myBean", myBean);
    }

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

SpringApplicationRunListener Extension

Implementing SpringApplicationRunListener enables hooks at various lifecycle stages (starting, environmentPrepared, contextPrepared, etc.). Example:

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 app;
    private final String[] args;
    public IntervenRunListener(SpringApplication app, String[] args) { this.app = app; this.args = args; }
    @Override public void starting() { System.out.println("IntervenRunListener starting"); }
    @Override public void environmentPrepared(ConfigurableEnvironment env) { System.out.println("environmentPrepared"); }
    @Override public void contextPrepared(ConfigurableApplicationContext ctx) { System.out.println("contextPrepared"); }
    @Override public void contextLoaded(ConfigurableApplicationContext ctx) { System.out.println("contextLoaded"); }
    @Override public void started(ConfigurableApplicationContext ctx) { System.out.println("started"); }
    @Override public void running(ConfigurableApplicationContext ctx) { System.out.println("running"); }
    @Override public void failed(ConfigurableApplicationContext ctx, Throwable ex) { System.out.println("failed"); }
}

Register it in spring.factories under org.springframework.boot.SpringApplicationRunListener .

ApplicationRunner and CommandLineRunner Extensions

These interfaces run custom logic after the application context is ready. Typical uses include database initialization, cache warm‑up, and environment checks.

package org.zyf.javabasic.springextend.runext;

import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.ApplicationArguments;
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!");
    }
}
package org.zyf.javabasic.springextend.runext;

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

@Component
public class EnvironmentChecker implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("EnvironmentChecker DatabaseConnection checkConnection!");
        System.out.println("EnvironmentChecker FileStorage checkWriteAccess!");
    }
}
package org.zyf.javabasic.springextend.runext;

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

@Component
public class StartupTasks implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("StartupTasks configService loadConfig");
        System.out.println("StartupTasks cacheService initialize");
    }
}

A sample command‑line tool for importing users demonstrates how CommandLineRunner can accept arguments:

package org.zyf.javabasic.springextend.runext;

import com.google.common.collect.Lists;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import org.zyf.javabasic.common.User;
import java.util.List;

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

Performance Optimizations for Faster Spring Boot Startup

The article concludes with a checklist of common techniques to shorten launch time, such as reducing unnecessary dependencies, fine‑tuning auto‑configuration, enabling lazy loading with @Lazy , applying compile‑time optimizations via Maven --add‑opens arguments, lowering log levels, and leveraging caching mechanisms.

BackendPerformanceOptimizationconfigurationSpringBootapplicationcontextinitializerApplicationRunnerCommandLineRunner
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.