Spring Boot 详解
什么是 Spring Boot
Spring Boot 是 Spring 框架的一个子项目,它简化了 Spring 应用的初始搭建和开发过程。Spring Boot 遵循"约定优于配置"的原则,让开发者能够快速创建独立运行、生产级别的 Spring 应用程序。
为什么选择 Spring Boot?
- 快速开发:内嵌服务器,无需部署 WAR 文件
- 简化配置:自动配置 Spring 和第三方库
- 生产就绪:提供生产环境监控、健康检查等功能
- 无代码生成:无需 XML 配置
- 丰富的生态系统:与 Spring 生态完美集成
Spring Boot 核心特性
1. 自动配置(Auto-Configuration)
Spring Boot 会根据 classpath 中的依赖自动配置 Spring 应用。这是 Spring Boot 最核心的特性。
2. 起步依赖(Starter Dependencies)
Spring Boot 提供了一系列的 starter 依赖,简化了 Maven/Gradle 配置:
3. 内嵌服务器
Spring Boot 内嵌了 Tomcat、Jetty 或 Undertow 服务器,无需部署到外部服务器。
Spring Boot 核心架构原理
整体架构图
Spring Boot 的整体架构采用了分层设计,将复杂的应用开发简化为几个核心模块。自动配置模块是 Spring Boot 的灵魂,它通过智能分析 classpath 中的依赖,自动配置 Spring 应用所需的各种组件。起步依赖模块提供了预配置的依赖组合,开发者只需要引入一个 starter 就能获得完整的相关功能。内嵌服务器模块让应用能够独立运行,无需外部服务器环境。这三个核心模块通过条件注解系统进行协调,确保只加载必要的配置,通过配置属性系统提供灵活的配置能力,并通过监控管理模块提供生产环境的运维支持。
自动配置原理详解
Spring Boot 的自动配置是其最核心的特性,它通过以下机制实现:
1. 自动配置流程图
自动配置流程是 Spring Boot 启动过程中的核心环节。当应用启动时,首先通过 @SpringBootApplication 注解启用自动配置功能。这个注解内部包含了 @EnableAutoConfiguration,它会激活 AutoConfigurationImportSelector 来扫描和选择需要加载的自动配置类。选择器会读取 classpath 中所有 META-INF/spring.factories 文件,获取所有候选的自动配置类。然后通过条件注解系统对这些配置类进行过滤,只加载满足条件的配置类。最后,Spring 容器会创建这些配置类中定义的 Bean,完成应用的自动配置过程。
2. 自动配置核心组件
@EnableAutoConfiguration 注解:这是自动配置的入口,它通过 @Import(AutoConfigurationImportSelector.class) 导入自动配置选择器。
AutoConfigurationImportSelector:负责选择要导入的自动配置类,它会:
- 读取
META-INF/spring.factories文件 - 获取所有候选的自动配置类
- 根据条件注解决定是否加载配置类
spring.factories 文件:定义了自动配置类的全限定名,格式如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
3. 条件注解过滤机制
Spring Boot 使用条件注解来决定是否加载配置类,这些注解包括:
- @ConditionalOnClass:当指定的类存在于 classpath 中时
- @ConditionalOnMissingClass:当指定的类不存在于 classpath 中时
- @ConditionalOnBean:当指定的 Bean 存在时
- @ConditionalOnMissingBean:当指定的 Bean 不存在时
- @ConditionalOnProperty:根据配置属性决定
- @ConditionalOnWebApplication:当应用是 Web 应用时
启动流程详解
Spring Boot 启动流程图
Spring Boot 的启动流程是一个精心设计的序列化过程。应用从 main() 方法开始,调用 SpringApplication.run() 方法启动整个应用。首先创建 SpringApplication 对象,这个对象会推断应用类型(是 Web 应用还是普通应用),并设置相应的初始化器和监听器。然后执行 run() 方法,在这个过程中会准备应用环境,创建 ApplicationContext 容器,并刷新容器以加载所有的 Bean。最后执行 ApplicationRunner 和 CommandLineRunner 接口的实现,这些接口允许开发者在应用启动完成后执行一些初始化逻辑。整个启动过程体现了 Spring Boot 的"约定优于配置"理念,大部分配置都是自动完成的。
详细启动步骤
步骤 1:创建 SpringApplication 对象
- 推断应用类型(Web 应用还是普通应用)
- 设置初始化器(ApplicationContextInitializer)
- 设置监听器(ApplicationListener)
步骤 2:执行 run() 方法
- 创建 ApplicationContext
- 准备环境(Environment)
- 创建 ApplicationContext
- 刷新 ApplicationContext
- 执行 ApplicationRunner 和 CommandLineRunner
步骤 3:自动配置加载过程
// AutoConfigurationImportSelector.selectImports() 方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 1. 获取所有候选的自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 2. 去重
configurations = removeDuplicates(configurations);
// 3. 根据条件注解过滤
configurations = filter(configurations, autoConfigurationMetadata);
// 4. 触发自动配置导入事件
fireAutoConfigurationImportEvents(configurations, exclusions);
return StringUtils.toStringArray(configurations);
}
核心注解详解
@SpringBootApplication
这是 Spring Boot 应用的主注解,它组合了以下三个注解:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
等价于:
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class DemoApplication {
// ...
}
详细解释:
- @Configuration:标识这是一个配置类,相当于 XML 配置文件
- @EnableAutoConfiguration:启用自动配置机制
- @ComponentScan:启用组件扫描,自动扫描并注册 Bean
@EnableAutoConfiguration
这是自动配置的核心注解,它的工作原理:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
关键点:
- 通过
@Import(AutoConfigurationImportSelector.class)导入自动配置选择器 AutoConfigurationImportSelector会读取META-INF/spring.factories文件- 根据条件注解决定是否加载配置类
@RestController
用于创建 RESTful Web 服务的控制器:
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/users")
public List<User> getUsers() {
return userService.findAll();
}
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.save(user);
}
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
}
@RestController = @Controller + @ResponseBody
@Service
标识业务逻辑层组件:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> findAll() {
return userRepository.findAll();
}
public User save(User user) {
return userRepository.save(user);
}
}
@Repository
标识数据访问层组件:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByEmail(String email);
Optional<User> findByUsername(String username);
}
@Component
通用组件注解,Spring 会自动扫描并注册为 Bean:
@Component
public class EmailService {
public void sendEmail(String to, String subject, String content) {
// 发送邮件逻辑
}
}
@Configuration
标识配置类,相当于 XML 配置文件:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create()
.url("jdbc:mysql://localhost:3306/demo")
.username("root")
.password("password")
.build();
}
@Bean
public UserService userService() {
return new UserService();
}
}
@Bean
用于声明一个 Bean:
@Configuration
public class BeanConfig {
@Bean
@Primary // 当有多个同类型Bean时,优先使用这个
public UserService userService() {
return new UserService();
}
@Bean
@Qualifier("adminUserService") // 指定Bean名称
public UserService adminUserService() {
return new AdminUserService();
}
}
自动装配机制
什么是自动装配?
自动装配是 Spring 容器自动注入依赖的过程,无需手动配置。
自动装配流程图
自动装配是 Spring 框架的核心特性之一,它让开发者无需手动配置 Bean 之间的依赖关系。当 Spring 容器启动时,它会扫描所有带有 @Component 注解的类,并为它们创建 Bean 实例。在创建 Bean 的过程中,Spring 会分析每个 Bean 的依赖关系,查找容器中是否有匹配的 Bean 可以注入。如果找到匹配的 Bean,Spring 会自动将其注入到需要的地方。这个过程完全自动化,大大简化了配置工作,提高了开发效率。
@Autowired 注解
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // 字段注入
@Autowired
public UserService(UserRepository userRepository) { // 构造器注入
this.userRepository = userRepository;
}
@Autowired
public void setUserRepository(UserRepository userRepository) { // Setter注入
this.userRepository = userRepository;
}
}
注入方式优先级
- 构造器注入(推荐)
- Setter 注入
- 字段注入
@Qualifier 注解
当有多个同类型的 Bean 时,使用 @Qualifier 指定具体的 Bean:
@Service
public class UserService {
@Autowired
@Qualifier("mysqlUserRepository")
private UserRepository userRepository;
}
@Primary 注解
当有多个同类型的 Bean 时,标记为主要的 Bean:
@Repository
@Primary
public class MySQLUserRepository implements UserRepository {
// 实现
}
@Repository
public class H2UserRepository implements UserRepository {
// 实现
}
@Value 注解
注入配置属性:
@Component
public class EmailService {
@Value("${app.email.host}")
private String emailHost;
@Value("${app.email.port:587}")
private int emailPort;
@Value("#{systemProperties['user.home']}")
private String userHome;
}
条件注解详解
条件注解分类图
条件注解系统是 Spring Boot 自动配置的核心机制,它通过不同类型的条件注解来控制配置类的加载。类条件注解用于检查 classpath 中是否存在特定的类,Bean 条件注解用于检查 Spring 容器中是否存在特定的 Bean,属性条件注解用于根据配置属性来决定是否加载配置,应用类型条件注解用于根据应用类型(Web 或非 Web)来决定配置的加载。这种设计让 Spring Boot 能够根据实际的环境和需求,智能地选择需要加载的配置,避免了不必要的配置加载,提高了应用的启动速度和运行效率。
@ConditionalOnClass
当指定的类存在于 classpath 中时,才加载配置:
@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {
// 配置内容
}
@ConditionalOnMissingClass
当指定的类不存在于 classpath 中时,才加载配置:
@Configuration
@ConditionalOnMissingClass("org.springframework.jdbc.core.JdbcTemplate")
public class JdbcTemplateAutoConfiguration {
// 配置内容
}
@ConditionalOnBean
当指定的 Bean 存在时,才加载配置:
@Configuration
@ConditionalOnBean(DataSource.class)
public class JdbcTemplateAutoConfiguration {
// 配置内容
}
@ConditionalOnMissingBean
当指定的 Bean 不存在时,才加载配置:
@Configuration
@ConditionalOnMissingBean(name = "dataSource")
public class DataSourceAutoConfiguration {
// 配置内容
}
@ConditionalOnProperty
根据配置属性决定是否加载配置:
@Configuration
@ConditionalOnProperty(prefix = "spring.datasource", name = "enabled", havingValue = "true", matchIfMissing = true)
public class DataSourceAutoConfiguration {
// 配置内容
}
@ConditionalOnWebApplication
当应用是 Web 应用时,才加载配置:
@Configuration
@ConditionalOnWebApplication
public class WebAutoConfiguration {
// 配置内容
}
@ConditionalOnNotWebApplication
当应用不是 Web 应用时,才加载配置:
@Configuration
@ConditionalOnNotWebApplication
public class NonWebAutoConfiguration {
// 配置内容
}
自定义自动配置
自定义自动配置流程图
自定义自动配置是 Spring Boot 生态系统中非常重要的一部分,它允许开发者创建可重用的配置模块。创建自定义自动配置的过程包括定义配置类、使用条件注解控制加载条件、创建配置属性类来管理配置参数、在 spring.factories 文件中注册配置类、将配置打包为 Starter 模块,最终让其他项目能够通过简单的依赖引入来使用这些配置。这种机制让 Spring Boot 的生态系统变得非常丰富,各种框架和库都可以通过这种方式与 Spring Boot 无缝集成。
1. 创建自动配置类
@Configuration
@ConditionalOnClass(UserService.class)
@EnableConfigurationProperties(UserProperties.class)
public class UserAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public UserService userService(UserProperties properties) {
UserService userService = new UserService();
userService.setName(properties.getName());
return userService;
}
}
2. 创建配置属性类
@ConfigurationProperties(prefix = "app.user")
public class UserProperties {
private String name = "default";
private String email;
// getters and setters
}
3. 创建 spring.factories 文件
在 src/main/resources/META-INF/spring.factories 中:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.config.UserAutoConfiguration
4. 使用自定义自动配置
在 application.properties 中:
app.user.name=张三
app.user.email=zhangsan@example.com
Spring Boot 配置系统
配置加载优先级图
Spring Boot 的配置系统采用了分层的优先级设计,确保配置的灵活性和可覆盖性。命令行参数具有最高的优先级,这允许在运行时动态修改配置。JNDI 属性主要用于 Java EE 环境中的配置。Java 系统属性通过 System.getProperties() 获取,常用于设置 JVM 级别的配置。操作系统环境变量提供了跨平台的配置方式。配置文件(如 application.properties 或 application.yml)是最常用的配置方式,支持不同环境的配置文件。@ConfigurationProperties 注解的类允许将配置映射到 Java 对象,提供类型安全的配置访问。最后,默认值作为配置的兜底方案,确保应用在没有任何外部配置的情况下也能正常运行。
配置文件类型
Spring Boot 支持多种配置文件格式:
- application.properties:传统属性文件格式
- application.yml:YAML 格式,层次结构清晰
- application.yaml:YAML 格式的另一种扩展名
配置文件示例
application.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo
username: root
password: password
jpa:
hibernate:
ddl-auto: update
show-sql: true
server:
port: 8080
logging:
level:
com.example: DEBUG
application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
server.port=8080
logging.level.com.example=DEBUG
Spring Boot 监控与管理
Actuator 监控端点
Spring Boot Actuator 提供了生产就绪的功能,帮助监控和管理应用:
常用监控端点
/actuator/health - 应用健康状态
/actuator/info - 应用信息
/actuator/metrics - 应用指标
/actuator/env - 环境变量
/actuator/configprops - 配置属性
/actuator/beans - Bean 信息
/actuator/mappings - 请求映射
/actuator/threaddump - 线程转储
/actuator/heapdump - 堆转储
健康检查配置
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
面试常见问题
Q1: Spring Boot 自动配置的原理是什么?
A: Spring Boot 自动配置的原理包括以下几个步骤:
- @EnableAutoConfiguration 注解:启用自动配置功能
- AutoConfigurationImportSelector:选择要导入的自动配置类
- spring.factories 文件:定义自动配置类的全限定名
- 条件注解:根据条件决定是否加载配置类
- @Configuration 注解:将配置类注册为 Spring Bean
Q2: @SpringBootApplication 注解包含哪些注解?
A: @SpringBootApplication 包含三个核心注解:
@Configuration // 标识这是一个配置类
@EnableAutoConfiguration // 启用自动配置
@ComponentScan // 启用组件扫描
Q3: Spring Boot 的启动流程是怎样的?
A: Spring Boot 启动流程:
- 创建 SpringApplication 对象
- 执行 run() 方法
- 创建 ApplicationContext
- 准备环境(Environment)
- 刷新 ApplicationContext
- 执行 ApplicationRunner 和 CommandLineRunner
Q4: 如何自定义自动配置?
A: 自定义自动配置的步骤:
- 创建配置类,使用 @Configuration 注解
- 使用条件注解控制配置的加载
- 在 META-INF/spring.factories 中注册配置类
- 创建配置属性类(可选)
Q5: @Autowired 和 @Resource 的区别是什么?
A: 主要区别:
- @Autowired:Spring 提供的注解,默认按类型装配
- @Resource:Java 提供的注解,默认按名称装配
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // 按类型装配
@Resource(name = "mysqlUserRepository")
private UserRepository userRepository; // 按名称装配
}
Q6: 如何禁用特定的自动配置?
A: 有几种方式:
- 使用 @EnableAutoConfiguration 的 exclude 属性:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class DemoApplication {
// ...
}
- 使用配置属性:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
- 使用 @ConditionalOnProperty:
@Configuration
@ConditionalOnProperty(name = "spring.datasource.enabled", havingValue = "false")
public class DataSourceAutoConfiguration {
// ...
}
Q7: Spring Boot 中的条件注解有哪些?
A: 常用的条件注解:
- @ConditionalOnClass:当指定的类存在时
- @ConditionalOnMissingClass:当指定的类不存在时
- @ConditionalOnBean:当指定的 Bean 存在时
- @ConditionalOnMissingBean:当指定的 Bean 不存在时
- @ConditionalOnProperty:根据配置属性
- @ConditionalOnWebApplication:当是 Web 应用时
- @ConditionalOnNotWebApplication:当不是 Web 应用时
Q8: 如何自定义 Starter?
A: 创建自定义 Starter 的步骤:
- 创建自动配置模块:
@Configuration
@ConditionalOnClass(MyService.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService() {
return new MyService();
}
}
- 创建 spring.factories 文件:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration
- 创建 Starter 模块:
<dependency>
<groupId>com.example</groupId>
<artifactId>my-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
最佳实践
1. 使用构造器注入
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
2. 合理使用条件注解
@Configuration
@ConditionalOnClass(DataSource.class)
@ConditionalOnProperty(prefix = "spring.datasource", name = "enabled", havingValue = "true")
public class DataSourceAutoConfiguration {
// 配置内容
}
3. 使用配置属性类
@ConfigurationProperties(prefix = "app")
@Component
public class AppProperties {
private String name;
private String version;
// getters and setters
}
4. 自定义自动配置时提供合理的默认值
@Configuration
@ConditionalOnClass(EmailService.class)
@EnableConfigurationProperties(EmailProperties.class)
public class EmailAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public EmailService emailService(EmailProperties properties) {
EmailService emailService = new EmailService();
emailService.setHost(properties.getHost());
emailService.setPort(properties.getPort());
return emailService;
}
}
5. 使用 @Primary 和 @Qualifier 解决 Bean 冲突
@Configuration
public class DataSourceConfig {
@Bean
@Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Qualifier("secondaryDataSource")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
总结
Spring Boot 通过自动配置、起步依赖、内嵌服务器等特性,大大简化了 Spring 应用的开发。它遵循"约定优于配置"的原则,让开发者能够快速创建生产就绪的应用程序。
关键要点:
- 自动配置:根据 classpath 自动配置 Spring 应用
- 核心注解:@SpringBootApplication、@EnableAutoConfiguration、@ConditionalOnClass 等
- 条件注解:控制配置类的加载条件
- 自动装配:@Autowired、@Qualifier、@Primary 等
- 自定义配置:通过 spring.factories 和条件注解
通过深入理解这些核心概念,可以更好地使用 Spring Boot 进行开发,并在面试中展示对框架的深度理解。
