Master Spring Boot Auto-Configuration: Beans, Conditions, and Custom Starters
This article explains how Spring Boot auto‑configuration works, how to locate candidate configurations, use various @Conditional annotations, and build a custom starter—including naming conventions, property keys, and a complete logging starter example with code snippets.
Understanding Auto-Configuration Beans
At the core, Spring Boot auto‑configuration is implemented with standard @Configuration classes, guarded by @Conditional annotations such as @ConditionalOnClass and @ConditionalOnMissingBean to ensure they apply only when the relevant classes are present and no user‑defined configuration exists.
You can inspect the spring-boot-autoconfigure source (see META-INF/spring.factories ) to see the provided @Configuration classes.
Locating Candidate Auto‑Configurations
Spring Boot scans for META-INF/spring.factories in each jar. The file lists configuration classes under the EnableAutoConfiguration key, for example:
<code>org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.pack.bus.autoconfigure.BusAutoConfiguration,\
com.pack.bus.autoconfigure.BusWebAutoConfiguration
</code>Auto‑configuration classes must not be picked up by component scanning; they should be imported explicitly.
Ordering can be controlled with @AutoConfigureAfter , @AutoConfigureBefore or @AutoConfigureOrder . The order only affects bean definition registration, not the actual bean creation order, which is determined by dependencies.
Conditional Annotations
Typical auto‑configuration classes include one or more @Conditional annotations. Common examples are @ConditionalOnMissingBean and the many @Conditional… annotations provided by Spring Boot.
Class Conditions : @ConditionalOnClass , @ConditionalOnMissingClass – include a configuration based on the presence or absence of a class.
Bean Conditions : @ConditionalOnBean , @ConditionalOnMissingBean – include based on the existence of a bean.
Property Conditions : @ConditionalOnProperty – include when a Spring environment property matches criteria.
Resource Conditions : @ConditionalOnResource – include when a specific resource is available.
Web Application Conditions : @ConditionalOnWebApplication , @ConditionalOnNotWebApplication – include based on the type of web application.
War Deployment Condition : @ConditionalOnWarDeployment – include for traditional WAR deployments.
SpEL Expression Condition : @ConditionalOnExpression – include based on a SpEL expression result.
When using class‑level conditions as meta‑annotations, the name attribute must be used to reference classes by name.
Creating Your Own Starter
Naming : Use a distinct namespace; avoid the spring-boot prefix unless you intend official support. Typically a starter is named acme-spring-boot-starter and its auto‑configuration module acme-spring-boot .
Configuration Keys : Keep keys in a unique namespace, not colliding with Spring Boot’s own keys (e.g., server , management ).
Provide Javadoc for each property.
<code>@ConfigurationProperties("acme")
public class AcmeProperties {
/** Whether to check the location of acme resources. */
private boolean checkLocation = true;
/** Timeout for establishing a connection to the acme server. */
private Duration loginTimeout = Duration.ofSeconds(3);
}
</code>Full Example – Logging Starter
Auto‑configuration class :
<code>@Configuration
@EnableConfigurationProperties(LogsProperties.class)
@ConditionalOnProperty(prefix = "logs", name = "enabled", havingValue = "true")
@EnableAspectJAutoProxy
public class LogsAutoConfiguration {
private static final Logger logger = LoggerFactory.getLogger(LogsAutoConfiguration.class);
@Resource
private LogsProperties logsProperties;
@Bean
public AspectJExpressionPointcutAdvisor logAdvisor() {
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
logger.info("执行表达式:{}", logsProperties.getPointcut());
advisor.setExpression(logsProperties.getPointcut());
advisor.setAdvice(new SystemAroundOperator());
return advisor;
}
}
</code>Custom annotation :
<code>@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemLog {
/** <p>操作说明</p> */
String value() default "";
}
</code>Properties class :
<code>@ConfigurationProperties(prefix = "logs")
public class LogsProperties {
/** 切入点定义<br/> 示例:execution(public * com.pack.controller.*.*(..)) */
private String pointcut;
/** 是否开启日志功能 */
private boolean enabled = true;
}
</code>Advice implementation :
<code>public class SystemAroundOperator implements MethodInterceptor {
private static final Logger logger = LoggerFactory.getLogger(SystemAroundOperator.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
long start = System.currentTimeMillis();
Method method = invocation.getMethod();
SystemLog annoLog = null;
if (method.isAnnotationPresent(SystemLog.class)) {
annoLog = method.getAnnotation(SystemLog.class);
String value = annoLog.value();
try {
Object result = invocation.proceed();
Long execTime = System.currentTimeMillis() - start;
logger.info("{}, 业务执行时间:{} ms", value, execTime);
return result;
} catch (Throwable t) {
Long execTime = System.currentTimeMillis() - start;
logger.info("{}, 业务执行时间:{} ms,发生异常信息:{}", value, execTime, t.getMessage());
throw t;
}
}
return invocation.proceed();
}
}
</code>Register the auto‑configuration in META-INF/spring.factories :
<code>org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.pack.config.LogsAutoConfiguration
</code>The two images illustrate the auto‑configuration flow.
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.