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:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.pack.bus.autoconfigure.BusAutoConfiguration,\
com.pack.bus.autoconfigure.BusWebAutoConfigurationAuto‑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.
@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);
}Full Example – Logging Starter
Auto‑configuration class :
@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;
}
}Custom annotation :
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemLog {
/** <p>操作说明</p> */
String value() default "";
}Properties class :
@ConfigurationProperties(prefix = "logs")
public class LogsProperties {
/** 切入点定义<br/> 示例:execution(public * com.pack.controller.*.*(..)) */
private String pointcut;
/** 是否开启日志功能 */
private boolean enabled = true;
}Advice implementation :
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();
}
}Register the auto‑configuration in META-INF/spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.pack.config.LogsAutoConfigurationThe two images illustrate the auto‑configuration flow.
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.
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.
