1. Spring Boot 核心优势
Spring Boot 的核心优势在于约定优于配置,它通过自动配置机制大幅简化了 Spring 应用的搭建和开发过程。
传统 Spring 开发需要大量 XML 配置或 Java Config:
java
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("123456");
return new HikariDataSource(config);
}
@Bean
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource());
return factory.getObject();
}
}
Spring Boot 只需引入依赖即可:
yaml
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456
2. @SpringBootApplication 解析
2.1 三个核心注解
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
public @interface SpringBootApplication {
// 指定要扫描的包(默认当前包及其子包)
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
Class<?>[] exclude() default {};
// 指定自动配置要排除的类
String[] excludeName() default {};
// 指定扫描的包
String[] basePackages() default {};
}
2.2 三个注解的作用
| 注解 | 作用 |
|---|---|
@SpringBootConfiguration |
标识这是一个 Spring Boot 配置类,等价于 @Configuration |
@EnableAutoConfiguration |
启用自动配置机制 |
@ComponentScan |
组件扫描,默认扫描当前包及其子包中的 @Component |
3. @EnableAutoConfiguration 原理
3.1 注解定义
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// 配置类名称,用于排除
String[] exclude() default {};
// 排除的配置类名称
String[] excludeName() default {};
// 配置类搜索路径
String[] value() default {};
}
3.2 自动配置导入选择器
@EnableAutoConfiguration 通过 @Import 导入 AutoConfigurationImportSelector,该类实现了 ImportSelector 接口:
java
public class AutoConfigurationImportSelector
implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 获取自动配置类
List<String> configurations = getAutoConfigurations(annotationMetadata);
// 排除用户已手动配置的类
configurations = removeDuplicates(configurations);
// 排除明确排除的类
Set<String> exclusions = getExclusions(annotationMetadata, configurations);
configurations.removeAll(exclusions);
// 过滤:检查条件注解是否满足
configurations = filter(configurations, autoConfigurationMetadata);
// 生成 @Import 需要的类名数组
String[] autoConfigurations =
configurations.toArray(new String[0]);
// 触发 AutoConfigurationImportEvent 事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return autoConfigurations;
}
}
3.3 自动配置类加载流程
@SpringBootApplication 启动
扫描 @EnableAutoConfiguration
AutoConfigurationImportSelector.selectImports
SpringFactoriesLoader.loadFactoryNames
META-INF/spring.factories
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
过滤不满足条件的配置类
返回需要导入的配置类
注册到 Spring 容器
4. 自动配置类加载机制
4.1 Spring Boot 2.7+ 变化
Spring Boot 2.7 之前使用 META-INF/spring.factories:
properties
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
Spring Boot 2.7+ 推荐使用 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
properties
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (每行一个)
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
4.2 Spring Boot 3.x
Spring Boot 3.x 完全移除了 spring.factories,只支持 AutoConfiguration.imports 文件。
4.3 loadFactoryNames 实现
java
public abstract class SpringFactoriesLoader {
public static List<String> loadFactoryNames(
Class<?> factoryType,
@Nullable ClassLoader classLoader) {
// factoryType = EnableAutoConfiguration.class
String factoryTypeName = factoryType.getName();
// 从 classpath 加载所有 META-INF/spring.factories
// 并解析为 Properties
result = loadSpringFactories(classLoader);
// 获取对应类型的值
return result.getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(
@Nullable ClassLoader classLoader) {
// 缓存
if (cache.containsKey(classLoader)) {
return cache.get(classLoader);
}
// 加载所有 spring.factories 文件
Enumeration<URL> urls = classLoader.getResources(
"META-INF/spring.factories");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
// 解析 Properties
Properties properties = PropertiesLoaderUtils.loadProperties(url);
// 合并到 result
result.addAll(properties);
}
cache.put(classLoader, result);
return result;
}
}
5. 自动配置条件注解
Spring Boot 使用条件注解控制配置类的生效条件。
5.1 常用条件注解
| 注解 | 作用 |
|---|---|
@ConditionalOnClass |
当 classpath 存在指定类时生效 |
@ConditionalOnMissingClass |
当 classpath 不存在指定类时生效 |
@ConditionalOnBean |
当容器中存在指定 Bean 时生效 |
@ConditionalOnMissingBean |
当容器中不存在指定 Bean 时生效 |
@ConditionalOnProperty |
当配置属性满足条件时生效 |
@ConditionalOnResource |
当资源存在时生效 |
@ConditionalOnWebApplication |
当是 Web 应用时生效 |
5.2 条件注解示例
java
// 只有存在 Druid 数据源时才配置
@ConditionalOnClass(DruidDataSource.class)
@Configuration
public class DruidConfig {
@ConditionalOnMissingBean(DataSource.class)
@Bean
public DataSource dataSource() {
return new DruidDataSource();
}
}
// 只有配置了 spring.redis.host 时才配置
@ConditionalOnProperty(prefix = "spring.redis", name = "host")
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(
RedisConnectionFactory connectionFactory) {
return new RedisTemplate<>(connectionFactory);
}
}
// 只有在 Web 应用中才配置
@ConditionalOnWebApplication
@Configuration
public class WebMvcConfig {
// Web 相关配置
}
5.3 条件注解原理
java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Conditional(OnClassCondition.class)
public @interface ConditionalOnClass {
Class<?>[] value() default {};
String[] name() default {};
}
@Conditional 是 Spring 4.0 引入的通用条件注解,OnClassCondition 是其具体实现:
java
@Order(Ordered.HIGHEST_PRECEDENCE)
class OnClassCondition implements ConfigurationCondition {
@Override
public ConditionOutcome getMatchOutcome(
ConditionContext context,
AnnotatedTypeMetadata metadata) {
// 获取 @ConditionalOnClass 注解的属性
MultiValueMap<String, Object> attributes =
metadata.getAllAnnotationAttributes(
ConditionalOnClass.class.getName());
List<Object> classesToCheck = attributes.get("value");
// 检查 classpath 是否存在这些类
for (Object classToCheck : classesToCheck) {
if (!ClassUtils.isPresent(
classToCheck.toString(),
context.getClassLoader())) {
// 不存在,返回不匹配
return ConditionOutcome.noMatch(
"@ConditionalOnClass " + classToCheck + " not present");
}
}
return ConditionOutcome.match();
}
}
6. 自动配置执行流程
6.1 SpringApplication 启动流程
AutoConfiguration ApplicationContext SpringApplication main() AutoConfiguration ApplicationContext SpringApplication main() run(args) createApplicationContext() refresh(context) invokeBeanFactoryPostProcessors() 处理 @Configuration 类的 @Bean 加载 AutoConfiguration 按条件过滤 注册 AutoConfiguration Bean ApplicationContext 准备完毕
6.2 配置类解析
Spring Boot 的自动配置类本质上是一个 @Configuration 类:
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(EmbeddedServletContainer.class)
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class WebServerAutoConfiguration {
@Bean
@ConditionalOnMissingBean(TomcatServletWebServerFactory.class)
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
7. 自定义 Starter
7.1 命名规范
| 类型 | 命名规范 | 示例 |
|---|---|---|
| 官方 Starter | spring-boot-starter-* |
spring-boot-starter-web |
| 第三方 Starter | *-spring-boot-starter |
druid-spring-boot-starter |
7.2 实现步骤
第一步:创建自动配置类
java
@Configuration
@ConditionalOnProperty(prefix = "myapp", name = "enabled",
havingValue = "true", matchIfMissing = true)
public class MyAppAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() {
return new MyService();
}
}
第二步:创建 spring.factories 或 imports 文件
# META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.myapp.MyAppAutoConfiguration
或
# META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.example.myapp.MyAppAutoConfiguration
第三步:创建配置属性类
java
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private String name = "default";
private int timeout = 3000;
// getters and setters
}
第四步:在启动类启用
java
@SpringBootApplication
@EnableConfigurationProperties(MyAppProperties.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
7.3 使用自定义 Starter
yaml
# application.yml
myapp:
enabled: true
name: my-app
timeout: 5000
java
@RestController
public class TestController {
@Autowired
private MyService myService;
@GetMapping("/test")
public String test() {
return myService.sayHello();
}
}
8. 自动配置源码层级
8.1 核心层级
Spring Boot 启动类
@SpringBootApplication
@EnableAutoConfiguration
AutoConfigurationImportSelector
SpringFactoriesLoader
META-INF/spring.factories
META-INF/spring/xxx.imports
加载所有 AutoConfiguration
@Conditional 条件过滤
实例化配置类
注册 Bean
8.2 配置类注册流程
java
// AbstractApplicationContext.refresh()
public void refresh() {
// ...
// 7. 初始化 BeanFactory 扩展
invokeBeanFactoryPostProcessors(beanFactory);
// ...
// 11. 初始化所有单例 Bean
finishBeanFactoryInitialization(beanFactory);
}
9. 常见自动配置类
9.1 DataSourceAutoConfiguration
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@Conditional(DataSourceAutoConfiguration.PooledDataSourceCondition.class)
@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
@Import(DataSourceConfiguration.Hikari.class)
protected static class Hikari {
// 配置 HikariCP 连接池
}
}
9.2 RedisAutoConfiguration
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RedisTemplate<String, Object> redisTemplate(
RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置序列化器
return template;
}
@Bean
@ConditionalOnMissingBean
public StringRedisTemplate stringRedisTemplate(
RedisConnectionFactory connectionFactory) {
return new StringRedisTemplate(connectionFactory);
}
}
9.3 WebMvcAutoConfiguration
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication
@ConditionalOnClass({ WebMvcConfigurer.class })
@EnableConfigurationProperties({ WebMvcProperties.class })
@Import({ WebMvcAutoConfiguration.EnableWebMvcConfiguration.class })
public class WebMvcAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager")
ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService")
FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider")
ResourceUrlProvider resourceUrlProvider) {
// 配置请求映射
}
}
10. 最佳实践
10.1 排除不需要的自动配置
java
// 方式1:启动类排除
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
RedisAutoConfiguration.class
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// 方式2:application.yml 排除
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
10.2 查看自动配置报告
bash
# 启用 debug 模式
java -jar app.jar --debug
# 或 application.yml
spring:
main:
log-startup-info: true
输出类似:
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:
-----------------
DataSourceAutoConfiguration
- @ConditionalOnClass found on class 'javax.sql.DataSource'
(OnClassCondition)
- @ConditionalOnMissingBean (types: javax.sql.DataSource;SearchStrategy: all)
did not find any beans (OnBeanCondition)
Negative matches:
-----------------
RedisAutoConfiguration
- @ConditionalOnClass did not find 'org.springframework.data.redis.core.RedisOperations'
(OnClassCondition)
10.3 自定义配置优先级
java
// 1. 配置属性类(最高优先级)
// application.yml 中配置
// 2. @Bean 定义
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
// 3. 自动配置默认值
// application.yml 未配置时使用
11. 总结
Spring Boot 自动配置是其核心优势,理解其原理对面试和开发都非常重要。
- @SpringBootApplication 组合了
@Configuration、@EnableAutoConfiguration、@ComponentScan三个注解 - 自动配置 通过
SpringFactoriesLoader加载META-INF/spring.factories或AutoConfiguration.imports文件 - 条件注解 (
@ConditionalOnClass、@ConditionalOnBean等)控制配置类的生效条件 - 配置类 本质上是一个标注了
@Configuration的普通 Spring 配置类 - 自定义 Starter 需要创建自动配置类和对应的配置文件
掌握这些知识点,能够帮助你更好地理解 Spring Boot 的工作原理,也能够自定义 Starter 封装公共组件。