Day29 补一下Spring Boot

1. Spring Boot 概述

1.1 什么是 Spring Boot

Spring Boot 是基于 Spring 框架的开发框架,它通过”约定优于配置”的理念,简化了 Spring 应用的初始搭建和开发过程。Spring Boot 并不是对 Spring 功能的增强,而是提供了一种快速使用 Spring 的方式。

核心设计理念:

  • 约定优于配置:提供合理的默认值,减少手动配置
  • 开箱即用:集成常用第三方库的默认配置
  • 自动配置:根据类路径自动配置 Spring 应用

1.2 Spring Boot vs Spring Framework

特性Spring FrameworkSpring Boot
配置繁琐的 XML/Java 配置自动配置,约定优于配置
部署需要外置 Tomcat内嵌 Tomcat,直接运行
依赖手动管理版本冲突Starter 依赖管理,自动版本管理
开发效率较低,配置繁琐极高,快速启动
监控需要手动集成内置 Actuator 监控端点
生产支持需要额外配置内置生产级特性

1.3 Spring Boot 核心特性

▼
mermaid
复制代码
graph TB A[Spring Boot] --> B[自动配置] A --> C[Starter 依赖] A --> D[内嵌服务器] A --> E[生产级特性] A --> F[无代码生成] A --> G[XML 配置可选] B --> B1[根据类路径自动配置] C --> C1[简化依赖管理] D --> D1[Tomcat/Jetty/Undertow] E --> E1[监控/健康检查/Metrics]

特性详解:

  1. 自动配置:Spring Boot 根据类路径中的依赖自动配置 Bean,大大减少了手动配置的工作量。
  2. Starter 依赖:提供了一系列开箱即用的依赖包,每个 Starter 都包含了一组相关的依赖和自动配置。
  3. 内嵌服务器:内嵌了 Tomcat、Jetty 或 Undertow,无需部署 WAR 包,直接运行 JAR 包。
  4. 生产级特性:内置了健康检查、指标监控、外部化配置等生产级特性。
  5. 无代码生成:Spring Boot 不会生成代码,而是通过字节码增强和动态代理实现功能。

核心原理

2.1 Spring Boot 启动流程

▼
mermaid
复制代码
sequenceDiagram participant Main as main() participant SA as SpringApplication participant EP as Environment participant AC as ApplicationContext participant RC as RefreshContext Main->>SA: 创建 SpringApplication SA->>SA: 推断应用类型 SA->>SA: 加载 BootstrapRegister SA->>EP: 准备 Environment SA->>SA: 打印 Banner SA->>SA: 创建 ApplicationContext SA->>AC: 加载自动配置 SA->>AC: 刷新上下文 AC->>RC: 调用 refresh() RC->>RC: 扫描 Bean 定义 RC->>RC: 实例化 Bean RC->>RC: 执行后置处理器 SA->>Main: 启动完成

启动流程详细解析:

  1. 创建 SpringApplication:根据类路径推断应用类型(SERVLET、REACTIVE 等)
  2. 准备 Environment:
    • 加载配置文件(application.yml/properties)
    • 加载系统属性和环境变量
    • 加载命令行参数
  3. 创建 ApplicationContext:根据应用类型创建合适的容器
  4. 刷新上下文:
    • 执行 BeanFactoryPostProcessor
    • 注册 BeanPostProcessor
    • 实例化单例 Bean
  5. 启动应用:调用 CommandLineRunner 和 ApplicationRunner

2.2 @SpringBootApplication 注解

▼
java
复制代码
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootConfiguration // 标识为配置类 @EnableAutoConfiguration // 启用自动配置 @ComponentScan( // 组件扫描 excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) } ) public @interface SpringBootApplication { // ... }

注解分解:

  1. @SpringBootConfiguration:本质上就是 @Configuration,标识这是一个配置类
  2. @EnableAutoConfiguration:开启自动配置,是 Spring Boot 的核心
  3. @ComponentScan:自动扫描当前包及其子包下的 @Component、@Service、@Repository 等

2.3 SpringApplication 核心方法

▼
java
复制代码
public class SpringApplication { /** * 创建 SpringApplication 实例 */ public SpringApplication(Class<?>... primarySources) { this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = WebApplicationType.deduceFromClasspath(); this.bootstrapRegistryInitializers = new ArrayList<>( getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class)); setListeners(getSpringFactoriesInstances(ApplicationListener.class)); } /** * 运行应用 */ public ConfigurableApplicationContext run(String... args) { long startTime = System.currentTimeMillis(); // 1. 创建 BootstrapContext DefaultBootstrapContext bootstrapContext = createBootstrapContext(); // 2. 准备 Environment ConfigurableEnvironment environment = prepareEnvironment(bootstrapContext, args); // 3. 创建 ApplicationContext prepareContext(bootstrapContext, environment, args); // 4. 刷新上下文 context = refreshContext(context); // 5. 调用 Runner callRunners(context, args); return context; } }

3. 自动配置机制

3.1 自动配置原理

▼
mermaid
复制代码
graph TD A[启动应用] --> B[加载主配置类] B --> C["@EnableAutoConfiguration"] C --> D[Import AutoConfigurationImportSelector] D --> E[读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports] E --> F[获取所有候选配置类] F --> G["@Conditional 注解过滤"] G --> H[过滤掉不符合条件的配置] H --> I[应用生效的配置] I --> J[注册到 Spring 容器]

自动配置原理详解:

Spring Boot 的自动配置通过以下步骤实现:

  1. @EnableAutoConfiguration 注解导入 AutoConfigurationImportSelector
  2. AutoConfigurationImportSelector 从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中读取所有自动配置类
  3. 对每个自动配置类,根据 @Conditional 系列注解进行过滤,只注册符合条件的 Bean
  4. 将过滤后的自动配置类注册到 Spring 容器

3.2 条件注解体系

注解说明应用场景
@ConditionalOnClass类路径中存在指定类检测是否引入了某个依赖
@ConditionalOnMissingClass类路径中不存在指定类避免与已有配置冲突
@ConditionalOnBean容器中存在指定 Bean依赖其他组件存在
@ConditionalOnMissingBean容器中不存在指定 Bean提供默认实现,允许覆盖
@ConditionalOnProperty配置文件中有指定属性根据配置开启/关闭功能
@ConditionalOnExpressionSpEL 表达式为 true复杂条件判断
@ConditionalOnWebApplicationWeb 应用环境仅在 Web 应用中生效
@ConditionalOnNotWebApplication非 Web 应用环境仅在非 Web 应用中生效
@ConditionalOnJava指定 Java 版本版本兼容性控制
@ConditionalOnResource资源存在检查配置文件是否存在

3.3 条件注解匹配原理

▼
java
复制代码
/** * 条件注解的底层实现 */ public interface Condition { /** * 判断条件是否匹配 */ boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata); } /** * 具体实现示例:@ConditionalOnClass */ class OnClassCondition extends SpringBootCondition { @Override public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) { // 获取注解属性 List<String> onClasses = getClasses(metadata, "value"); List<String> onMissingClasses = getClasses(metadata, "missing"); // 检查类是否存在 boolean match = checkClasses(context.getClassLoader(), onClasses, true) && checkClasses(context.getClassLoader(), onMissingClasses, false); return match ? ConditionOutcome.match() : ConditionOutcome.noMatch("Required classes not found"); } }

3.4 自定义自动配置

▼
java
复制代码
@Configuration @ConditionalOnClass(DataSource.class) @EnableConfigurationProperties(DataSourceProperties.class) public class DataSourceAutoConfiguration { @Bean @ConditionalOnMissingBean public DataSource dataSource(DataSourceProperties properties) { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(properties.getUrl()); dataSource.setUsername(properties.getUsername()); dataSource.setPassword(properties.getPassword()); dataSource.setDriverClassName(properties.getDriverClassName()); return dataSource; } }

3.5 禁用自动配置

▼
java
复制代码
@SpringBootApplication( exclude = {DataSourceAutoConfiguration.class, RedisAutoConfiguration.class} ) public class DemoApplication { // ... }
▼
yaml
复制代码
# application.yml 方式 spring: autoconfigure: exclude: - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration

3.6 自动配置报告

启用自动配置报告,查看哪些配置生效/未生效:

▼
yaml
复制代码
# application.yml debug:true

4. Starter 机制

4.1 Starter 原理

▼
mermaid
复制代码
graph LR A[Starter 依赖] --> B[引入自动配置] A --> C[引入所需依赖] B --> D[自动配置类] B --> E[条件注解] C --> F[第三方库] C --> G[Spring 组件] D --> H[配置类注册] E --> I[按需生效]

Starter 设计原理:

  1. 依赖聚合:Starter 是一个空的 JAR 包,主要用于聚合相关依赖
  2. 自动配置:通过 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件注册自动配置类
  3. 条件装配:自动配置类通过 @Conditional 注解实现按需装配

命名规范:

  • 官方 Starter:spring-boot-starter-*
  • 第三方 Starter:*-spring-boot-starter

4.2 常用 Starter

Starter功能描述
spring-boot-starter-webWeb 应用开发,包含 Tomcat、Spring MVC
spring-boot-starter-data-jpaJPA 数据访问
spring-boot-starter-data-redisRedis 数据访问
spring-boot-starter-security安全认证
spring-boot-starter-aopAOP 面向切面编程
spring-boot-starter-test测试支持
spring-boot-starter-actuator监控和健康检查
spring-boot-starter-validation数据校验
mybatis-spring-boot-starterMyBatis 集成

4.3 自定义 Starter

目录结构

▼
text
复制代码
my-spring-boot-starter/ ├── pom.xml ├── src/ │ └── main/ │ ├── java/ │ │ └── com/example/starter/ │ │ ├── MyStarterAutoConfiguration.java │ │ ├── MyStarterProperties.java │ │ └── MyService.java │ └── resources/ │ └── META-INF/ │ └── spring/ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports

引入依赖文件

创建Maven项目,pom.xml里引入spring-boot-starter作为基础依赖

▼
xml
复制代码
<project ...> <groupId>com.example</groupId> <artifactId>my-starter</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>

自动配置类

▼
java
复制代码
@Configuration @EnableConfigurationProperties(MyStarterProperties.class) @ConditionalOnClass(MyService.class) @ConditionalOnProperty( prefix = "my.starter", name = "enabled", havingValue = "true", matchIfMissing = true ) public class MyStarterAutoConfiguration { @Bean @ConditionalOnMissingBean public MyService myService(MyStarterProperties properties) { return new MyService(properties); } }

属性配置类

▼
java
复制代码
@ConfigurationProperties(prefix = "my.starter") @Data public class MyStarterProperties { private String name = "default"; private Integer maxRetries = 3; private Boolean enabled = true; }

注册文件

▼
text
复制代码
com.example.starter.MyStarterAutoConfiguration

5. 配置管理

5.1 配置文件优先级

▼
mermaid
复制代码
graph TD A[配置优先级] --> B[命令行参数] A --> C[操作系统环境变量] A --> D[Java 系统属性] A --> E[JAR 外部配置文件] A --> F[JAR 内部配置文件] A --> G["@PropertySource 注解"] A --> H[默认配置] B --> I[优先级最高] H --> J[优先级最低]

配置加载顺序(从高到低):

  1. 命令行参数
  2. 操作系统环境变量
  3. Java 系统属性
  4. JAR 外部配置文件
  5. JAR 内部配置文件
  6. @PropertySource 注解指定的配置文件
  7. 默认属性

5.2 配置文件格式

▼
yaml
复制代码
# application.yml server: port:8080 servlet: context-path: /api spring: application: name: demo-application profiles: active: dev # 自定义配置 app: name: Demo App description: Spring Boot Demo config: timeout:3000 retry: max:3 delay:1000

5.3 多环境配置

▼
text
复制代码
src/main/resources/ ├── application.yml # 默认配置 ├── application-dev.yml # 开发环境 ├── application-test.yml # 测试环境 └── application-prod.yml # 生产环境
▼
yaml
复制代码
# application.yml spring: profiles: active: ${ENV:dev} # 默认 dev,可通过环境变量覆盖

5.4 配置属性绑定

▼
java
复制代码
/** * 方式1: @ConfigurationProperties * 适用场景:复杂配置,多级属性 */ @Component @ConfigurationProperties(prefix = "app") @Data @Validated public class AppConfig { @NotBlank(message = "应用名称不能为空") private String name; private String description; @Valid private Config config = new Config(); @Data public static class Config { @Min(value = 100, message = "超时时间至少100ms") private Integer timeout; @Valid private Retry retry = new Retry(); @Data public static class Retry { @Min(value = 1, message = "最大重试次数至少1次") @Max(value = 10, message = "最大重试次数不超过10次") private Integer max; private Long delay; } } }

5.5 配置加密

▼
xml
复制代码
<dependency> <groupId>com.github.ulisesbocchio</groupId> <artifactId>jasypt-spring-boot-starter</artifactId> <version>3.0.5</version> </dependency>
▼
yml
复制代码
jasypt: encryptor: password: ${JASYPT_PASSWORD} # 从环境变量获取 algorithm: PBEWithMD5AndDES app: password: ENC(加密后的密码)
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP