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