Master Spring Boot 3 Extension Points: Custom AutoConfiguration, ApplicationContext, and RunListeners
This article walks through Spring Boot 3's powerful extension points—including AutoConfigurationImportFilter, ApplicationContextFactory, SpringApplicationRunListener, and ApplicationContextInitializer—showing how to implement, register, and test custom behavior with complete code examples and configuration steps.
Environment: SpringBoot 3.2.5
1. Introduction
Spring Boot offers many powerful extension points that allow developers to intervene at key moments in the application lifecycle to implement custom logic. The article covers the following extension points:
AutoConfigurationImportFilter – limits auto‑configuration classes.
ApplicationContextFactory – creates the ApplicationContext used by SpringApplication.
SpringApplicationRunListener – defines events triggered at different startup stages.
ApplicationContextInitializer – runs before the container refresh to configure the context.
2. Practical Examples
2.1 AutoConfigurationImportFilter
By default Spring Boot provides three implementations: OnBeanCondition, OnClassCondition, and OnWebApplicationCondition. A custom implementation can be created as follows:
<code>public class PackClassCondition implements AutoConfigurationImportFilter, EnvironmentAware {
private Environment environment;
@Override
public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) {
boolean[] matchs = new boolean[autoConfigurationClasses.length];
for (int i = 0, len = matchs.length; i < len; i++) {
if (autoConfigurationClasses[i] != null && autoConfigurationClasses[i].equals(PackAutoConfiguration.class.getName())) {
Boolean ret = this.environment.getProperty("pack.app.enabled", Boolean.class, false);
matchs[i] = ret;
} else {
matchs[i] = true;
}
}
return matchs;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
</code>The filter checks whether the current class is PackAutoConfiguration and activates the auto‑configuration only when the property pack.app.enabled is true. Register it in META-INF/spring.factories :
<code>org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
com.pack.extension.autoImportfilter.PackClassCondition
</code>2.2 ApplicationContextFactory
This interface creates the ApplicationContext required by Spring Boot. A custom factory can decide which context to create based on the environment:
<code>public class PackApplicationContextFactory implements ApplicationContextFactory {
@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.SERVLET) ? null : createContext();
}
private ConfigurableApplicationContext createContext() {
System.err.println("使用自定义容器...");
return new PackApplicationContext();
}
public static class PackApplicationContext extends AnnotationConfigServletWebServerApplicationContext {
@Override
protected void prepareRefresh() {
System.err.println("准备执行容器核心方法refresh");
super.prepareRefresh();
}
}
}
</code>Register the factory in META-INF/spring.factories :
<code>org.springframework.boot.ApplicationContextFactory=\
com.pack.extension.contextfactory.PackApplicationContextFactory
</code>Running the application shows the custom ApplicationContext in use.
2.3 SpringApplicationRunListener
The interface defines callbacks for various startup phases. A simple custom listener can log messages at each stage:
<code>public class PackSpringApplicationRunListener implements SpringApplicationRunListener, Ordered {
@Override
public int getOrder() { return 1; }
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.err.println("ApplicationContext 创建并准备好, 还没有开始调用refresh方法");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
System.err.printf("上下文已经被刷新,并且应用程序已经启动,但 *Runners 尚未被调用, 应用程序启动所花费时间: %dms%n", timeTaken.toMillisPart());
}
}
</code>Register it in META-INF/spring.factories :
<code>org.springframework.boot.SpringApplicationRunListener=\
com.pack.extension.eventpublisher.PackSpringApplicationRunListener
</code>The listener can receive the SpringApplication instance and command‑line arguments via a constructor:
<code>private SpringApplication app;
private final String[] args;
public PackSpringApplicationRunListener(SpringApplication app, String[] args) {
this.app = app;
this.args = args;
System.err.printf("%s%s%n", app, Arrays.toString(this.args));
}
</code>Run the application with:
<code>java -jar App.jar --pack.title=xxxooo --pack.version=1.0.0
</code>2.4 ApplicationContextInitializer
This interface allows configuration before the container refresh. Example:
<code>public class PackApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext context) {
context.addApplicationListener(null);
context.addBeanFactoryPostProcessor(null);
context.getEnvironment().getConversionService().addConverter(null);
// ...
}
}
</code>Register it in META-INF/spring.factories :
<code>org.springframework.context.ApplicationContextInitializer=\
com.pack.extension.contextinitializer.PackApplicationContextInitializer
</code>The article demonstrates how to customize Spring Boot's startup process by implementing and registering these extension points, providing complete code snippets and configuration details.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
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.