Spring自动配置的实现原理

Spring自动配置的实现原理

Spring Boot 的自动配置是其最受欢迎的特性之一。理解自动配置原理,有助于自定义 Starter 和排查配置问题。

自动配置的入口

@SpringBootApplication

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

等价于

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application { }

@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
}

核心@Import(AutoConfigurationImportSelector.class)

AutoConfigurationImportSelector

加载流程

public class AutoConfigurationImportSelector implements 
DeferredImportSelector, BeanClassLoaderAware, ... {

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 获取自动配置条目
AutoConfigurationEntry autoConfigurationEntry =
getAutoConfigurationEntry(annotationMetadata);

// 2. 返回配置类列表
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}

读取 spring.factories

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, 
AnnotationAttributes attributes) {
// 从 META-INF/spring.factories 读取
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());

Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring.factories");

return configurations;
}

spring.factories 示例

# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration,\
com.example.OtherAutoConfiguration

过滤配置类

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata metadata) {
// 1. 读取所有候选配置
List<String> configurations = getCandidateConfigurations(metadata, attributes);

// 2. 去重
configurations = removeDuplicates(configurations);

// 3. 排除指定配置
Set<String> exclusions = getExclusions(metadata, attributes);
configurations.removeAll(exclusions);

// 4. 条件过滤(@ConditionalOnXxx)
configurations = getConfigurationClassFilter().filter(configurations);

// 5. 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);

return new AutoConfigurationEntry(configurations, exclusions);
}

条件注解

常用条件注解

注解 条件
@ConditionalOnClass classpath 中存在指定类
@ConditionalOnMissingClass classpath 中不存在指定类
@ConditionalOnBean 容器中存在指定 Bean
@ConditionalOnMissingBean 容器中不存在指定 Bean
@ConditionalOnProperty 指定属性满足条件
@ConditionalOnResource 存在指定资源
@ConditionalOnWebApplication 是 Web 应用
@ConditionalOnExpression SpEL 表达式为 true

示例

@Configuration
@ConditionalOnClass(DataSource.class) // classpath 有 DataSource
@ConditionalOnMissingBean(DataSource.class) // 容器中没有 DataSource Bean
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {

@Bean
@ConditionalOnMissingBean // 用户没定义时才创建
public DataSource dataSource(DataSourceProperties properties) {
return DataSourceBuilder.create()
.url(properties.getUrl())
.username(properties.getUsername())
.password(properties.getPassword())
.build();
}
}

自定义 Starter

创建步骤

1. 创建自动配置类

@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties.getName());
}
}

2. 创建配置属性类

@ConfigurationProperties(prefix = "my.service")
public class MyProperties {
private String name = "default";
private boolean enabled = true;

// getter/setter
}

3. 创建 spring.factories

# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.autoconfigure.MyAutoConfiguration

4. 使用 Starter

<dependency>
<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
my:
service:
name: myApp
enabled: true

自动配置报告

查看生效的自动配置

# 开启 DEBUG 日志
logging.level.org.springframework.boot.autoconfigure=DEBUG

# 或使用 --debug
java -jar app.jar --debug

自动配置报告

Positive matches:
-----------------
DataSourceAutoConfiguration matched:
- @ConditionalOnClass found required classes 'DataSource', ...
- @ConditionalOnMissingBean (types: DataSource; SearchStrategy: all) did not find any beans

Negative matches:
-----------------
ActiveMQAutoConfiguration:
Did not match:
- @ConditionalOnClass did not find required class 'javax.jms.ConnectionFactory'

排除自动配置

方式1:注解排除

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class Application { }

方式2:配置文件排除

spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

自动配置原理总结

@SpringBootApplication
└── @EnableAutoConfiguration
└── @Import(AutoConfigurationImportSelector)
└── selectImports()
├── 读取 META-INF/spring.factories
├── 加载所有 EnableAutoConfiguration 类
├── 排除指定配置
└── @Conditional 过滤
├── @ConditionalOnClass
├── @ConditionalOnBean
└── @ConditionalOnProperty

常见问题

1. 自动配置不生效

排查

# 1. 检查 spring.factories 路径和格式
# 2. 检查条件注解是否满足
# 3. 开启 DEBUG 查看报告

2. 配置冲突

解决

@Bean
@ConditionalOnMissingBean // 只在用户未定义时创建
public MyService myService() {
return new MyService();
}

3. 加载顺序

@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
public class MyAutoConfiguration { }

总结

Spring Boot 自动配置的核心机制:

  1. spring.factories:注册自动配置类
  2. @Conditional:条件过滤,按需加载
  3. @EnableConfigurationProperties:绑定配置
  4. @ConditionalOnMissingBean:允许用户覆盖

这个设计使得 Spring Boot 项目可以做到零配置启动,同时保留充分的自定义能力。


   转载规则


《Spring自动配置的实现原理》 小乐 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录