Why Does ApplicationContextInitializer Run Twice? Debugging Spring Boot Startup
This article explains the purpose of ApplicationContextInitializer in Spring Boot, shows how to implement custom conditions and initializers for environment‑specific configuration, and investigates why the initializer may execute twice when Spring Cloud Context is added, leading to bean duplication and port conflicts.
ApplicationContextInitializer Introduction
The initializer works on a ConfigurableApplicationContext (an ApplicationContext) and allows us to enhance the context before the refresh operation.
Business Scenario
In real‑world web applications we often need to programmatically initialize the application context, such as registering property sources (bootstrap/application properties) and dynamically activating different profiles based on the environment. For example, a recent project required loading different SDK parameters depending on whether the OS is Linux or Windows.
Custom Condition Implementation
Because of the large number of configuration items, we can customize @Conditional on a ConfigurationProperties bean.
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String property = context.getEnvironment().getProperty("os.name");
// ...
return property.contains("linux");
}
} @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({LinuxCondition.class})
public @interface ConditionOnLinux {}Due to the SDK’s overly complex configuration classes, this approach was eventually abandoned.
Custom ApplicationContextInitializer Implementation
Based on the context environment, we load resource directories and configuration files for different environments.
public class SelectApplicationContextInitializer implements ApplicationContextInitializer {
@Override
public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment env = context.getEnvironment();
MutablePropertySources mps = env.getPropertySources();
String property = env.getProperty("os.name");
if (property.contains("Mac OS X")) {
mps.addLast(new ResourcePropertySource(new ClassPathResource("linux.properties")));
} else {
mps.addLast(new ResourcePropertySource(new ClassPathResource("window.properties")));
}
}
}Problem: initialize Executes Twice
When the functionality is extracted into a starter and runs in a monolithic Spring Boot project, adding Spring Cloud Context causes the initializer to run twice.
SpringApplication.run
To locate the root cause, a breakpoint was set in SpringApplication.run.
BootstrapApplicationListener
The investigation reached the BootstrapApplicationListener.bootstrapServiceContext method.
We examined the bootstrapServiceContext method.
SpringApplicationBuilder builder = (new SpringApplicationBuilder(new Class[0]))
.profiles(environment.getActiveProfiles())
.bannerMode(Mode.OFF)
.environment(bootstrapEnvironment)
.registerShutdownHook(false)
.logStartupInfo(false)
.web(WebApplicationType.NONE);
SpringApplication builderApplication = builder.application();
if (builderApplication.getMainApplicationClass() == null) {
builder.main(application.getMainApplicationClass());
}
if (environment.getPropertySources().contains("refreshArgs")) {
builderApplication.setListeners(this.filterListeners(builderApplication.getListeners()));
}
builder.sources(BootstrapImportSelectorConfiguration.class);
ConfigurableApplicationContext context = builder.run(new String[0]);
context.setId("bootstrap");Truth Warning
Inside BootstrapApplicationListener, SpringApplicationBuilder triggers a restart; although Run is called twice, the first run does not start the container, leading to beans being loaded twice or port conflicts such as Tomcat.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
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.
