Spring Boot启动过程全面解析:从入门到精通
wptr33 2025-06-10 02:11 14 浏览
一、Spring Boot概述
Spring Boot是一个基于Spring框架的快速开发脚手架,它通过"约定优于配置"的原则简化了Spring应用的初始搭建和开发过程。
1.1 Spring Boot核心特性
特性 | 说明 | 生活化比喻 |
自动配置 | 根据依赖自动配置Spring应用 | 像智能家居系统,检测到新设备自动配置 |
起步依赖 | 简化依赖管理,传递性依赖自动处理 | 像套餐服务,点一个主菜自动配好辅料 |
命令行界面 | 支持Groovy脚本和命令行交互 | 像智能语音助手,通过命令控制应用 |
Actuator | 提供生产级监控和管理功能 | 像汽车仪表盘,实时显示运行状态 |
1.2 Spring Boot vs Spring vs Spring MVC
维度 | Spring Boot | Spring | Spring MVC |
定位 | 快速开发脚手架 | 全栈框架 | Web框架 |
配置 | 自动配置为主 | 手动配置 | 手动配置 |
依赖管理 | 起步依赖简化 | 需手动管理 | 需手动管理 |
部署 | 内嵌服务器 | 需外部服务器 | 需外部服务器 |
适用场景 | 微服务、快速开发 | 需要高度定制 | 传统Web应用 |
二、Spring Boot启动过程深度解析
2.1 启动流程概览
2.2 详细启动步骤分析
步骤1:main方法入口
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// 生活比喻:就像汽车的启动钥匙
SpringApplication.run(MyApplication.class, args);
}
}
步骤2:SpringApplication实例化
// SpringApplication构造方法核心代码分析
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 判断应用类型:Servlet、Reactive或None
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 初始化所有SpringBoot的初始化器(从META-INF/spring.factories加载)
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 初始化所有SpringBoot的监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主配置类(通过堆栈分析)
this.mainApplicationClass = deduceMainApplicationClass();
}
步骤3:运行SpringApplication
public ConfigurableApplicationContext run(String... args) {
// 1. 创建并启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2. 准备环境
ConfigurableEnvironment environment = prepareEnvironment(...);
// 3. 打印Banner(就是启动时的Spring标志)
Banner printedBanner = printBanner(environment);
// 4. 创建应用上下文
context = createApplicationContext();
// 5. 准备上下文
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 6. 刷新上下文(核心步骤)
refreshContext(context);
// 7. 执行Runner(ApplicationRunner和CommandLineRunner)
callRunners(context, applicationArguments);
stopWatch.stop();
return context;
}
2.3 关键组件详解
2.3.1 自动配置原理
@Target(ElementType.TYPE) // 指定该注解只能应用于类、接口或枚举类型
@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留,可通过反射获取
@Documented // 标记该注解应被包含在JavaDoc中
@Inherited // 标明该注解可被继承(子类会自动继承此注解)
@SpringBootConfiguration // 声明该类为Spring Boot配置类,底层继承自@Configuration
@EnableAutoConfiguration // 启用Spring Boot自动配置机制,根据依赖自动注册Bean
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), // 自定义过滤器,排除特定类型的组件
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) // 排除自动配置相关的类,避免重复注册
})
public @interface SpringBootApplication {
/**
* 配置属性:
* - exclude():指定需要排除的自动配置类
* - excludeName():通过类名排除自动配置类
* - proxyBeanMethods():控制@Bean方法是否代理(默认true)
*/
// 注解属性定义(示例):
// Class<?>[] exclude() default {};
// String[] excludeName() default {};
// boolean proxyBeanMethods() default true;
}
自动配置实现机制:
- @EnableAutoConfiguration 启用自动配置
- 从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports加载配置类
- 通过@Conditional系列注解条件化加载Bean
生活化示例:就像智能家居系统,当你买回一台新电视:
- 系统检测到新设备(类似Spring检测到依赖)
- 自动配置电视的电源、网络等(自动配置Bean)
- 如果检测到你是VIP用户,还会自动开通高级频道(条件化配置)
2.3.2 内嵌服务器启动
Tomcat启动流程:
- 检测到spring-boot-starter-web依赖
- 自动配置ServletWebServerFactory
- 创建服务器实例并启动
// 简化的Tomcat启动代码
public class TomcatWebServer implements WebServer {
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
this.tomcat = tomcat;
initialize();
if (autoStart) {
start(); // 启动Tomcat
}
}
}
三、Spring Boot配置详解
3.1 配置文件类型对比
类型 | 文件格式 | 加载顺序 | 特点 | 适用场景 |
properties | key=value | 1 | 简单直观 | 简单配置、老项目兼容 |
yml | 层级结构 | 2 | 支持复杂结构 | 微服务、复杂配置 |
yaml | 同yml | 同yml | 同yml | 同yml |
3.2 常用配置项解析
application.yml示例:
# 服务器配置(好比餐厅的门面设置)
server:
port: 8080 # 营业窗口号
servlet:
context-path: /api # 餐厅入口路径
# 数据库配置(好比餐厅的食材仓库)
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: chef # 仓库管理员
password: secret # 仓库密码
driver-class-name: com.mysql.cj.jdbc.Driver
# 日志配置(好比餐厅的监控系统)
logging:
level:
root: info # 常规监控级别
org.springframework.web: debug # 特别关注区域
3.3 自定义配置与读取
方式1:@Value注解
@Component
public class Restaurant {
@Value("${restaurant.name}") // 读取配置项
private String name;
@Value("${restaurant.tables:10}") // 带默认值
private int tableCount;
}
方式2:@ConfigurationProperties
@ConfigurationProperties(prefix = "restaurant")
@Data // Lombok注解,自动生成getter/setter
public class RestaurantProperties {
private String name;
private String address;
private List<String> specialties;
private Map<String, Double> prices;
}
// 使用示例
@RestController
@EnableConfigurationProperties(RestaurantProperties.class)
public class MenuController {
@Autowired
private RestaurantProperties properties;
@GetMapping("/menu")
public String showMenu() {
return "今日特色菜: " + properties.getSpecialties();
}
}
四、Spring Boot高级特性
4.1 条件化装配详解
Spring Boot提供了丰富的条件注解:
注解 | 说明 | 生活化比喻 |
@ConditionalOnClass | 类路径存在指定类时生效 | 厨房有烤箱才提供烤制服务 |
@ConditionalOnMissingBean | 容器中没有指定Bean时生效 | 没有主厨时才启用备用厨师 |
@ConditionalOnProperty | 配置属性满足条件时生效 | 周末才开放自助餐服务 |
@ConditionalOnWebApplication | Web环境下生效 | 只有堂食才提供餐具 |
代码示例:
@Configuration
public class KitchenConfiguration {
// 只有当Oven类存在时才创建BakingService
@Bean
@ConditionalOnClass(name = "com.example.Oven")
public BakingService bakingService() {
return new BakingService();
}
// 只有配置了restaurant.feature.buffet=true时才启用
@Bean
@ConditionalOnProperty(prefix = "restaurant.feature", name = "buffet", havingValue = "true")
public BuffetService buffetService() {
return new BuffetService();
}
}
4.2 自定义Starter开发
开发一个简单的餐厅服务Starter:
- 创建自动配置类:
@Configuration
@ConditionalOnClass(RestaurantService.class)
@EnableConfigurationProperties(RestaurantProperties.class)
public class RestaurantAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RestaurantService restaurantService(RestaurantProperties properties) {
return new DefaultRestaurantService(properties);
}
}
- 创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件:
com.example.restaurant.autoconfigure.RestaurantAutoConfiguration
- 添加配置元数据(用于IDE提示):
// META-INF/spring-configuration-metadata.json
{
"properties": [
{
"name": "restaurant.name",
"type": "java.lang.String",
"description": "The name of the restaurant."
},
{
"name": "restaurant.tables",
"type": "java.lang.Integer",
"description": "Number of tables available.",
"defaultValue": 10
}
]
}
4.3 监控与管理(Actuator)
Actuator提供了一系列生产就绪特性:
常用端点:
端点 | 路径 | 描述 | 生活化比喻 |
health | /actuator/health | 应用健康状态 | 餐厅卫生检查 |
info | /actuator/info | 应用基本信息 | 餐厅招牌和简介 |
metrics | /actuator/metrics | 应用指标 | 餐厅经营数据报表 |
loggers | /actuator/loggers | 日志配置管理 | 餐厅监控系统设置 |
mappings | /actuator/mappings | URL映射 | 餐厅座位表 |
配置示例:
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
metrics:
enabled: true
五、Spring Boot启动优化
5.1 启动性能优化策略
策略 | 实现方式 | 效果 | 注意事项 |
延迟初始化 | spring.main.lazy-initialization=true | 减少启动时间 | 可能导致首次请求响应慢 |
排除自动配置 | @SpringBootApplication(exclude={DataSourceAutoConfiguration.class}) | 减少不必要的配置 | 需确保不影响功能 |
组件扫描优化 | @ComponentScan(basePackages="com.myapp") | 减少扫描范围 | 不要漏掉必要组件 |
JVM参数调优 | -XX:TieredStopAtLevel=1 | 加快启动速度 | 影响峰值性能 |
5.2 类加载优化
Spring Boot 2.3+引入了分层JAR技术:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
</plugin>
分层结构:
- dependencies:依赖库
- spring-boot-loader:Spring Boot加载器
- snapshot-dependencies:快照依赖
- application:应用代码
六、常见问题与解决方案
6.1 启动问题排查表
问题现象 | 可能原因 | 解决方案 | 排查命令/工具 |
启动时报Bean创建失败 | 依赖缺失或配置错误 | 检查依赖和配置 | --debug模式启动 |
端口被占用 | 已有应用占用端口 | 更改端口或停止冲突应用 | netstat -ano |
自动配置不生效 | 条件不满足或扫描不到 | 检查@Conditional条件和组件扫描 | 启用自动配置报告(debug=true) |
启动慢 | 组件扫描范围大或依赖多 | 优化扫描范围,延迟初始化 | --trace模式启动 |
6.2 调试技巧
- 启用调试模式:
debug=true
- 查看自动配置报告: 报告会显示哪些自动配置类被应用/排除
- 使用启动监听器:
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
// 打印事件信息帮助调试
System.out.println("Received event: " + event.getClass().getSimpleName());
}
}
七、实战案例:餐厅管理系统
7.1 项目结构
restaurant-system
├── src/main/java
│ ├── com.example.restaurant
│ │ ├── config // 配置类
│ │ ├── controller // 控制器
│ │ ├── service // 服务层
│ │ ├── repository // 数据访问
│ │ └── model // 实体类
├── src/main/resources
│ ├── static // 静态资源
│ ├── templates // 模板文件
│ └── application.yml // 配置文件
7.2 核心代码实现
启动类:
@SpringBootApplication
public class RestaurantApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(RestaurantApplication.class);
// 添加初始化监听器
app.addListeners(new MyApplicationListener());
// 设置额外配置
app.setBannerMode(Banner.Mode.LOG);
app.run(args);
}
}
自定义Banner: 在src/main/resources下创建banner.txt:
____ _
| _ \ ___ ___ _ __ ___ _ __ | |_
| |_) / _ \/ __| '_ \ / _ \| '_ \| __|
| _ < __/\__ \ |_) | (_) | | | | |_
|_| \_\___||___/ .__/ \___/|_| |_|\__|
|_| v1.0.0
餐厅服务示例:
@Service
@Slf4j
public class RestaurantService implements ApplicationRunner {
@Autowired
private MenuService menuService;
@PostConstruct
public void init() {
log.info("餐厅准备营业...");
}
@Override
public void run(ApplicationArguments args) throws Exception {
log.info("今日菜单已加载: {}", menuService.getTodaySpecial());
}
@PreDestroy
public void cleanup() {
log.info("餐厅打烊,清理中...");
}
}
八、Spring Boot启动过程总结
8.1 核心生命周期回调
阶段 | 回调方式 | 执行时机 | 典型用途 |
初始化 | @PostConstruct | Bean初始化完成后 | 资源加载、数据预热 |
启动后 | ApplicationRunner | 应用完全启动后 | 初始化业务数据 |
启动后 | CommandLineRunner | 同ApplicationRunner | 命令行参数处理 |
销毁前 | @PreDestroy | 应用关闭前 | 资源释放、数据保存 |
写结尾时才发现跑题了,但没关系,人生不也经常跑偏?
头条对markdown的文章显示不太友好,想了解更多的可以关注微信公众号:“Eric的技术杂货库”,后期会有更多的干货以及资料下载。
相关推荐
- MySQL进阶五之自动读写分离mysql-proxy
-
自动读写分离目前,大量现网用户的业务场景中存在读多写少、业务负载无法预测等情况,在有大量读请求的应用场景下,单个实例可能无法承受读取压力,甚至会对业务产生影响。为了实现读取能力的弹性扩展,分担数据库压...
- 3分钟短文 | Laravel SQL筛选两个日期之间的记录,怎么写?
-
引言今天说一个细分的需求,在模型中,或者使用laravel提供的EloquentORM功能,构造查询语句时,返回位于两个指定的日期之间的条目。应该怎么写?本文通过几个例子,为大家梳理一下。学习时...
- 一文由浅入深带你完全掌握MySQL的锁机制原理与应用
-
本文将跟大家聊聊InnoDB的锁。本文比较长,包括一条SQL是如何加锁的,一些加锁规则、如何分析和解决死锁问题等内容,建议耐心读完,肯定对大家有帮助的。为什么需要加锁呢?...
- 验证Mysql中联合索引的最左匹配原则
-
后端面试中一定是必问mysql的,在以往的面试中好几个面试官都反馈我Mysql基础不行,今天来着重复习一下自己的弱点知识。在Mysql调优中索引优化又是非常重要的方法,不管公司的大小只要后端项目中用到...
- MySQL索引解析(联合索引/最左前缀/覆盖索引/索引下推)
-
目录1.索引基础...
- 你会看 MySQL 的执行计划(EXPLAIN)吗?
-
SQL执行太慢怎么办?我们通常会使用EXPLAIN命令来查看SQL的执行计划,然后根据执行计划找出问题所在并进行优化。用法简介...
- MySQL 从入门到精通(四)之索引结构
-
索引概述索引(index),是帮助MySQL高效获取数据的数据结构(有序),在数据之外,数据库系统还维护者满足特定查询算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构...
- mysql总结——面试中最常问到的知识点
-
mysql作为开源数据库中的榜一大哥,一直是面试官们考察的重中之重。今天,我们来总结一下mysql的知识点,供大家复习参照,看完这些知识点,再加上一些边角细节,基本上能够应付大多mysql相关面试了(...
- mysql总结——面试中最常问到的知识点(2)
-
首先我们回顾一下上篇内容,主要复习了索引,事务,锁,以及SQL优化的工具。本篇文章接着写后面的内容。性能优化索引优化,SQL中索引的相关优化主要有以下几个方面:最好是全匹配。如果是联合索引的话,遵循最...
- MySQL基础全知全解!超详细无废话!轻松上手~
-
本期内容提醒:全篇2300+字,篇幅较长,可搭配饭菜一同“食”用,全篇无废话(除了这句),干货满满,可收藏供后期反复观看。注:MySQL中语法不区分大小写,本篇中...
- 深入剖析 MySQL 中的锁机制原理_mysql 锁详解
-
在互联网软件开发领域,MySQL作为一款广泛应用的关系型数据库管理系统,其锁机制在保障数据一致性和实现并发控制方面扮演着举足轻重的角色。对于互联网软件开发人员而言,深入理解MySQL的锁机制原理...
- Java 与 MySQL 性能优化:MySQL分区表设计与性能优化全解析
-
引言在数据库管理领域,随着数据量的不断增长,如何高效地管理和操作数据成为了一个关键问题。MySQL分区表作为一种有效的数据管理技术,能够将大型表划分为多个更小、更易管理的分区,从而提升数据库的性能和可...
- MySQL基础篇:DQL数据查询操作_mysql 查
-
一、基础查询DQL基础查询语法SELECT字段列表FROM表名列表WHERE条件列表GROUPBY分组字段列表HAVING分组后条件列表ORDERBY排序字段列表LIMIT...
- MySql:索引的基本使用_mysql索引的使用和原理
-
一、索引基础概念1.什么是索引?索引是数据库表的特殊数据结构(通常是B+树),用于...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
程序员的开源月刊《HelloGitHub》第 71 期
-
详细介绍一下Redis的Watch机制,可以利用Watch机制来做什么?
-
假如有100W个用户抢一张票,除了负载均衡办法,怎么支持高并发?
-
如何将AI助手接入微信(打开ai手机助手)
-
Java面试必考问题:什么是乐观锁与悲观锁
-
redission YYDS spring boot redission 使用
-
SparkSQL——DataFrame的创建与使用
-
一文带你了解Redis与Memcached? redis与memcached的区别
-
如何利用Redis进行事务处理呢? 如何利用redis进行事务处理呢英文
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)