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 Framework | Spring 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]
特性详解:
- 自动配置:Spring Boot 根据类路径中的依赖自动配置 Bean,大大减少了手动配置的工作量。
- Starter 依赖:提供了一系列开箱即用的依赖包,每个 Starter 都包含了一组相关的依赖和自动配置。
- 内嵌服务器:内嵌了 Tomcat、Jetty 或 Undertow,无需部署 WAR 包,直接运行 JAR 包。
- 生产级特性:内置了健康检查、指标监控、外部化配置等生产级特性。
- 无代码生成: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: 启动完成
启动流程详细解析:
- 创建 SpringApplication:根据类路径推断应用类型(SERVLET、REACTIVE 等)
- 准备 Environment:
- 加载配置文件(application.yml/properties)
- 加载系统属性和环境变量
- 加载命令行参数
- 创建 ApplicationContext:根据应用类型创建合适的容器
- 刷新上下文:
- 执行 BeanFactoryPostProcessor
- 注册 BeanPostProcessor
- 实例化单例 Bean
- 启动应用:调用 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 { // ... }
注解分解:
- @SpringBootConfiguration:本质上就是 @Configuration,标识这是一个配置类
- @EnableAutoConfiguration:开启自动配置,是 Spring Boot 的核心
- @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 的自动配置通过以下步骤实现:
- @EnableAutoConfiguration 注解导入
AutoConfigurationImportSelector AutoConfigurationImportSelector从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中读取所有自动配置类- 对每个自动配置类,根据
@Conditional系列注解进行过滤,只注册符合条件的 Bean - 将过滤后的自动配置类注册到 Spring 容器
3.2 条件注解体系
| 注解 | 说明 | 应用场景 |
|---|---|---|
@ConditionalOnClass | 类路径中存在指定类 | 检测是否引入了某个依赖 |
@ConditionalOnMissingClass | 类路径中不存在指定类 | 避免与已有配置冲突 |
@ConditionalOnBean | 容器中存在指定 Bean | 依赖其他组件存在 |
@ConditionalOnMissingBean | 容器中不存在指定 Bean | 提供默认实现,允许覆盖 |
@ConditionalOnProperty | 配置文件中有指定属性 | 根据配置开启/关闭功能 |
@ConditionalOnExpression | SpEL 表达式为 true | 复杂条件判断 |
@ConditionalOnWebApplication | Web 应用环境 | 仅在 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 设计原理:
- 依赖聚合:Starter 是一个空的 JAR 包,主要用于聚合相关依赖
- 自动配置:通过
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件注册自动配置类 - 条件装配:自动配置类通过
@Conditional注解实现按需装配
命名规范:
- 官方 Starter:
spring-boot-starter-* - 第三方 Starter:
*-spring-boot-starter
4.2 常用 Starter
| Starter | 功能描述 |
|---|---|
| spring-boot-starter-web | Web 应用开发,包含 Tomcat、Spring MVC |
| spring-boot-starter-data-jpa | JPA 数据访问 |
| spring-boot-starter-data-redis | Redis 数据访问 |
| spring-boot-starter-security | 安全认证 |
| spring-boot-starter-aop | AOP 面向切面编程 |
| spring-boot-starter-test | 测试支持 |
| spring-boot-starter-actuator | 监控和健康检查 |
| spring-boot-starter-validation | 数据校验 |
| mybatis-spring-boot-starter | MyBatis 集成 |
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[优先级最低]
配置加载顺序(从高到低):
- 命令行参数
- 操作系统环境变量
- Java 系统属性
- JAR 外部配置文件
- JAR 内部配置文件
@PropertySource注解指定的配置文件- 默认属性
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个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
