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.
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=WARN6. 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.
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.
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.