Spring Boot
Spring Boot 是一个基于 Java 的开源应用框架,旨在简化 Spring 应用的初始搭建和开发过程。它由 Pivotal 团队提供,核心设计思想是"约定优于配置",通过提供开箱即用的默认配置,让开发者能更专注于业务逻辑的实现,而无需编写大量样板化的配置文件。
特性
- 自动配置 (Auto Configuration)
这是 Spring Boot 的灵魂。它能根据项目类路径中的依赖,自动配置 Spring 应用程序。例如,当项目中引入了数据库相关的库,Spring Boot 就会自动尝试配置数据源,极大地减少了手动配置的工作量。 - 内嵌服务器 (Embedded Server)
Spring Boot 内置了 Tomcat、Jetty 或 Undertow 等 Web 服务器。这意味着你无需将应用打包成 WAR 文件并部署到外部的服务器中,而是可以直接打包成一个可执行的 JAR 文件,通过java -jar命令即可启动应用,简化了部署流程。 - 起步依赖 (Starter Dependencies)
Spring Boot 提供了一系列名为 "Starter" 的依赖描述符。这些 Starter 将常用功能所需的依赖整合在一起,开发者只需引入一个 Starter(如spring-boot-starter-web),即可快速为项目添加 Web 开发能力,无需手动管理众多库的版本和兼容性。 - 生产就绪 (Production-Ready)
框架内置了如健康检查、指标监控、外部化配置等生产环境所需的功能(通过spring-boot-starter-actuator模块实现),方便对应用进行管理和监控。 - 零代码生成与无XML配置
Spring Boot 绝对没有代码生成,也完全不要求使用 XML 进行配置。它主要依靠注解和属性文件(如application.yml)来完成配置,使开发体验更加现代化和简洁。
自动配置 (Auto Configuration)原理
自动配置的旅程始于我们熟悉的 @SpringBootApplication 注解。它是一个组合注解,其中真正开启自动配置的是 @EnableAutoConfiguration。
java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@ComponentScan(excludeFilters = { ... })
// 核心在这里:导入了自动配置的选择器
@EnableAutoConfiguration
public @interface SpringBootApplication { ... }
@EnableAutoConfiguration 注解本身通过 @Import 导入了一个至关重要的类:AutoConfigurationImportSelector。
java
@AutoConfigurationPackage
// 关键:导入 AutoConfigurationImportSelector,它是自动配置的执行核心
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration { ... }
当 Spring 容器启动并处理到这个注解时,就会触发 AutoConfigurationImportSelector 的逻辑。
加载候选配置:AutoConfigurationImportSelector
AutoConfigurationImportSelector 实现了 DeferredImportSelector 接口,其核心方法是 selectImports。这个方法负责返回所有需要导入到 Spring 容器中的配置类的全限定名。
ImportSelector(立即执行)
当一个配置类通过@Import导入了一个实现ImportSelector接口的类时,Spring 会在解析该配置类的过程中,立即调用selectImports方法。这意味着它的执行时机较早,发生在处理当前配置类的@Bean、@ImportResource等其他注解之前。DeferredImportSelector(延迟执行)
DeferredImportSelector是ImportSelector的子接口。当一个配置类导入的是DeferredImportSelector的实现类时,Spring 会采取延迟处理 的策略。selectImports方法不会立即执行,而是被推迟到所有 普通的@Configuration配置类都被解析完成之后,才会被统一调用。
1. 获取自动配置条目 (getAutoConfigurationEntry)
selectImports 方法内部调用了 getAutoConfigurationEntry,这是整个流程的调度中心。我们可以从源码中清晰地看到它的四个核心步骤:
java
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata metadata) {
// 1. 加载所有候选的自动配置类
List<String> configurations = getCandidateConfigurations(metadata, attributes);
// 2. 去除重复的配置类
configurations = removeDuplicates(configurations);
// 3. 应用排除规则,例如通过 @EnableAutoConfiguration(exclude=...) 手动排除
Set<String> exclusions = getExclusions(metadata, attributes);
configurations.removeAll(exclusions);
// 4. 【最关键一步】应用条件注解进行过滤,只保留当前环境需要的配置
configurations = getConfigurationClassFilter().filter(configurations);
// ... 发布事件等后续操作
return new AutoConfigurationEntry(configurations, exclusions);
}
2. 读取配置清单 (getCandidateConfigurations)
getCandidateConfigurations 方法负责从固定的资源文件中加载所有候选的自动配置类。这正是"约定优于配置"的体现,Spring Boot 约定了这些配置类存放的位置。
java
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 核心:使用 SpringFactoriesLoader 从 classpath 下的特定文件中加载配置类名称
// 在 Spring Boot 2.7+ / 3.x 中,文件路径为 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), // 即 EnableAutoConfiguration.class
getBeanClassLoader()
);
// ... 校验逻辑
return configurations;
}
这个文件(AutoConfiguration.imports 或旧版的 spring.factories)就像一个"菜单",列出了 Spring Boot 提供的所有自动配置类,例如 DataSourceAutoConfiguration、WebMvcAutoConfiguration 等。
智能筛选:条件注解 (@Conditional)
加载了成百上千个候选配置类后,Spring Boot 并不会全部启用。getConfigurationClassFilter().filter(configurations) 这行代码是智能筛选的核心。
它利用 @Conditional 系列注解作为"过滤器",只有满足特定条件的配置类才会被最终选中。这确保了自动配置的"按需生效"。
| 条件注解 | 作用 | 源码示例 |
|---|---|---|
@ConditionalOnClass |
类路径下存在指定类时才生效 | @ConditionalOnClass(DataSource.class) |
@ConditionalOnMissingBean |
容器中不存在指定 Bean 时才生效 | @ConditionalOnMissingBean(DataSource.class) |
@ConditionalOnProperty |
配置文件存在指定属性时才生效 | @ConditionalOnProperty(name = "my.feature.enabled", ...) |
@ConditionalOnWebApplication |
当前是 Web 应用时才生效 | @ConditionalOnWebApplication(type = ...) |
以 WebMvcAutoConfiguration 为例,它的源码清晰地展示了多个条件注解的组合使用,确保只在 Web 环境下且相关类存在时才进行配置:
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
public class WebMvcAutoConfiguration {
// ... 自动配置 Web MVC 相关的 Bean
}
最终装配:Bean 的注册与创建
经过层层筛选后,最终胜出的自动配置类会被 Spring 当作普通的 @Configuration 类来处理。Spring 会解析这些类,并执行其中所有 @Bean 注解的方法,从而将框架所需的组件(如数据源、视图解析器等)注册到 IoC 容器中。
同时,这些配置类通常会配合 @ConfigurationProperties 注解,将 application.yml 或 application.properties 中的配置属性绑定到 Java 对象上,实现了配置的动态化。
总而言之,Spring Boot 的自动配置是一个高度自动化和智能化的过程,它通过 @EnableAutoConfiguration 触发,利用 AutoConfigurationImportSelector 加载候选配置,再通过 @Conditional 系列注解进行精确筛选,最终完成 Bean 的自动注册,完美诠释了"开箱即用"的开发体验。
自定义Starter
第一步:创建项目结构
Spring Boot 官方建议自定义 Starter 的命名格式为 xxx-spring-boot-starter。为了职责清晰,我们创建一个包含两个子模块的 Maven 项目:
hello-spring-boot-autoconfigure: 这是核心模块,包含所有的自动配置逻辑、业务代码和配置属性。hello-spring-boot-starter: 这是一个"空壳"模块,其唯一作用是作为依赖入口,它只包含对autoconfigure模块的依赖。
最终的项目结构如下:
html
hello-spring-boot-starter (父工程)
├── hello-spring-boot-autoconfigure
│ ├── src/main/java/com/example/hello/
│ │ ├── HelloService.java (业务服务类)
│ │ ├── HelloAutoConfiguration.java (自动配置类)
│ │ └── HelloProperties.java (配置属性类)
│ └── src/main/resources/META-INF/
│ └── spring.factories (自动配置注册文件)
└── hello-spring-boot-starter
└── pom.xml (依赖聚合)
第二步:实现 autoconfigure 模块
1. 编写业务服务类 (HelloService.java)
是你希望对外提供的核心功能,一个普通的 Java 类即可,无需任何 Spring 注解。
java
package com.example.hello;
public class HelloService {
private final String prefix;
public HelloService(String prefix) {
this.prefix = prefix;
}
public String sayHello(String name) {
return prefix + ", " + name + "!";
}
}
2. 编写配置属性类 (HelloProperties.java)
这个类用于将 application.yml 或 application.properties 中的配置绑定到 Java 对象中,让用户可以自定义行为。
java
package com.example.hello;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
// 默认前缀
private String prefix = "Hello";
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}
用户可以在他们的配置文件中这样设置:hello.prefix=Hi
3. 编写自动配置类 (HelloAutoConfiguration.java)
java
package com.example.hello;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
// 当类路径下存在 HelloService 时才生效,这是一种安全检查
@ConditionalOnClass(HelloService.class)
// 启用配置属性,将 HelloProperties 注册为 Bean 并绑定配置
@EnableConfigurationProperties(HelloProperties.class)
public class HelloAutoConfiguration {
// 当容器中没有 HelloService 这个 Bean 时,才创建并注册它
// 这保证了用户可以自己定义 HelloService 来覆盖默认配置
@Bean
@ConditionalOnMissingBean
public HelloService helloService(HelloProperties properties) {
return new HelloService(properties.getPrefix());
}
}
4. 注册自动配置类 (spring.factories)
这是让 Spring Boot 发现并加载你自定义配置类的关键。在 hello-spring-boot-autoconfigure 模块的 src/main/resources/META-INF/ 目录下,创建名为 spring.factories 的文件。
文件内容如下:
java
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.hello.HelloAutoConfiguration
这行配置告诉 Spring Boot:"在启动时,请加载 com.example.hello.HelloAutoConfiguration 这个类"。
注意 :在 Spring Boot 2.7+ 版本中,推荐使用新的
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件来替代spring.factories,内容只需写上自动配置类的全限定名即可。
第三步:实现 starter 模块
这个模块非常简单,它的 pom.xml 只需要声明对 autoconfigure 模块的依赖。
java
<!-- hello-spring-boot-starter/pom.xml -->
<project>
<!-- ... 其他项目信息 ... -->
<artifactId>hello-spring-boot-starter</artifactId>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-autoconfigure</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</project>
第四步:打包并使用
- 打包 :在父工程
hello-spring-boot-starter的根目录下,执行mvn clean install命令。这会将两个模块都安装到你本地的 Maven 仓库中。 - 使用 :现在,你可以在任何一个新的 Spring Boot 项目中引入你的 Starter。在
pom.xml中添加依赖:
java
<dependency>
<groupId>com.example</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
常用注解
启动与核心配置注解
| 注解 | 说明 | 典型应用场景 |
|---|---|---|
@SpringBootApplication |
核心元注解。它是一个组合注解,包含了 @SpringBootConfiguration、@EnableAutoConfiguration 和 @ComponentScan。 |
标注在主类上,作为 Spring Boot 应用的启动入口。 |
@EnableAutoConfiguration |
告诉 Spring Boot 根据类路径下的依赖(jar包)自动配置 Bean。 | 通常包含在 @SpringBootApplication 中,极少单独使用。 |
@SpringBootConfiguration |
标识当前类是一个配置类。它本质上是 @Configuration 的特化,用于标识 Spring Boot 的主配置类。 |
标注在主启动类上,表明该类也可以定义 Bean。 |
@AutoConfigurationPackage |
将主类所在包(及子包)注册为自动配置包,用于 JPA 扫描实体或自定义 Starter 扫描。 | 包含在 @SpringBootApplication 中,决定了 @EntityScan 的默认范围。 |
自动配置与条件注解
| 注解 | 说明 | 典型应用场景 |
|---|---|---|
@ConditionalOnClass |
当类路径下存在指定的类时,配置才生效。 | 检测是否引入了 DataSource.class,从而决定是否配置数据库连接池。 |
@ConditionalOnMissingBean |
当 Spring 容器中不存在指定的 Bean 时,配置才生效。 | 提供默认实现(如默认的 DataSource),允许用户自定义 Bean 进行覆盖。 |
@ConditionalOnProperty |
当配置文件(application.yml)中存在指定属性且值匹配时,配置才生效。 |
根据 my.feature.enabled=true 配置来决定是否开启某个功能模块。 |
@ConditionalOnWebApplication |
当当前应用是 Web 应用时,配置才生效。 | 自动配置 DispatcherServlet 或 Web 相关的拦截器。 |
@ConditionalOnNotWebApplication |
当当前应用不是 Web 应用时,配置才生效。 | 在非 Web 环境(如命令行应用)中配置特定的批处理逻辑。 |
@ConditionalOnResource |
当类路径下存在指定资源文件时,配置才生效。 | 检测到 logback.xml 时才配置特定的日志工厂。 |
@AutoConfigureAfter / @AutoConfigureBefore |
指定自动配置类的加载顺序,确保在某个自动配置类之后或之前加载。 | 自定义配置类需要在全局默认配置(如 DataSourceAutoConfiguration)之后生效时使用。 |
属性绑定与外部化配置
| 注解 | 说明 | 典型应用场景 |
|---|---|---|
@ConfigurationProperties |
将配置文件(application.yml)中的属性值批量绑定到 Java Bean 中。支持松散绑定(如 my-prop 绑定到 myProp)。 |
定义一个 ServerProperties 类,自动读取 server.port、server.address 等配置。 |
@EnableConfigurationProperties |
开启对 @ConfigurationProperties 的支持,并将指定的 Bean 注册到容器中。 |
在自定义 Starter 的配置类上使用,确保属性类能被 Spring 管理。 |
其他注解
| 注解 | 说明 | 典型应用场景 |
|---|---|---|
@ImportAutoConfiguration |
导入指定的自动配置类,但不触发全量的 @EnableAutoConfiguration。 |
在测试类或非主启动类中,手动引入某些自动配置功能(如 HttpAutoConfiguration)。 |
@TestConfiguration |
用于定义测试专用的配置。它不会被主应用程序上下文扫描到,除非显式导入。 | 在测试代码中定义一些仅用于测试环境的 Bean 或 Mock 配置。 |
@SpringBootConfiguration |
这是一个特殊的 @Configuration,专门用于标识 Spring Boot 应用的配置类。 |
通常作为 @SpringBootApplication 的一部分出现。 |