SpringBoot
阅读提示
推荐按“为什么用 -> 自动配置 -> 启动流程 -> 常见落地问题”顺序复习。
面试回答时别只背注解,尽量结合你项目里真实的启动、配置、异步和跨域实践。
本文以 Spring Boot 3.5.x、Spring Framework 6.2.x、Java 17+ 为基准;Servlet Web 部分按 Spring MVC 说明。虚拟线程需要 Java 21+。不同大版本的自动配置注册方式与默认执行器可能不同,不能直接套用。
1、什么是 Spring Boot?它解决了什么问题?
回答提示:
- 核心价值:简化 Spring 项目搭建与配置。
- 通过“约定优于配置 + 自动配置 + Starter”,降低开发门槛。
- Web 应用可使用内嵌服务器独立运行;非 Web 应用也可使用 Boot,并不要求启动服务器。
参考回答:
- Spring Boot 是一套快速构建 Spring 应用的脚手架体系。
- 它把重复配置模板化,让我们更关注业务开发而不是框架装配。
2、Spring Boot 的核心特性有哪些?
- 自动配置(Auto Configuration)。
- 起步依赖(Starter)。
- 内嵌服务器(Tomcat/Jetty/Undertow)。
- 外部化配置(properties/yaml/环境变量/命令行)。
- 生产可观测能力(Actuator)。
3、@SpringBootApplication 由哪些注解组成?
回答提示:
@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan
参考回答:
@SpringBootApplication本质是组合注解,分别负责“配置类标识、自动配置开关、组件扫描”。- 默认组件扫描从启动类所在包向下进行,因此启动类通常放在业务根包;自动配置类的发现走专门的导入机制,不靠扫描所有依赖包。
4、Spring Boot 自动配置原理是什么?
回答提示:
- 入口是
@EnableAutoConfiguration。 - 通过自动配置类 + 条件注解按需生效。
- 依赖类路径与环境配置决定最终装配结果。
参考回答:
- 自动配置不是“无脑全配”,而是“条件成立才装配”。
- 常见条件注解包括
@ConditionalOnClass、@ConditionalOnMissingBean、@ConditionalOnProperty。
机制补充(Boot 3.5.x): @EnableAutoConfiguration 通过 AutoConfigurationImportSelector 导入候选配置,候选来自依赖 JAR 中的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。随后按类路径、属性和已有 Bean 等条件决定是否注册配置与 Bean。声明自己的 Bean 只会使具有相应缺失条件的默认 Bean 退让,并不保证关闭整套自动配置。
Starter 引入依赖 → imports 提供候选配置 → 条件匹配 → 注册所需 Bean例如,类路径有 JDBC 相关类并不代表一定能成功创建数据源,还需满足数据源配置等条件。可在启动时传入 --debug 查看条件评估报告,区分“条件未匹配”与“匹配后初始化失败”。参见官方 EnableAutoConfiguration API、自动配置注册与条件。
5、配置文件什么时候加载到内存?
回答提示:
- 在应用启动早期的 Environment 准备阶段加载。
- 在
SpringApplication.run()流程中,先构建 Environment,再刷新容器。
参考回答:
- Boot 3.5.x 的标准 Config Data(如
application.yml)由ConfigDataEnvironmentPostProcessor在 Environment 准备阶段加载,早于 ApplicationContext 刷新;不是所有来源的配置都在此时加载,@PropertySource要到刷新期间才加入,来不及影响早期读取的logging.*、spring.main.*。 - 常见来源的覆盖顺序(从低到高)为:Config Data < 操作系统环境变量 < Java 系统属性 < 命令行参数;这是常见子集,测试属性等还有额外优先级。Environment 保留多个 PropertySource,取值时按优先级查找,不是简单把所有配置拼成一个文件。
参见官方 外部化配置及优先级、ConfigDataEnvironmentPostProcessor API。
6、Spring Boot 启动流程怎么讲更清晰?
- 创建
SpringApplication,确定应用类型并准备监听器等启动设施。 - 准备 Environment,加载标准 Config Data。
- 创建、准备 ApplicationContext,加载启动配置源。
- 刷新容器:解析配置及自动配置、注册 Bean 定义、初始化非懒加载单例;Servlet Web 应用的内嵌服务器也在刷新过程中创建并通过生命周期启动,并非刷新后的独立总步骤。
- 刷新完成后发布
ApplicationStartedEvent,调用ApplicationRunner/CommandLineRunner。 - Runner 成功完成后发布
ApplicationReadyEvent;启动失败则进入失败处理,不会正常到达 Ready。
懒加载 Bean 可以推迟到首次使用才初始化,因此 Ready 不等于每个 Bean 都已实例化。参见官方 SpringApplication 与应用事件顺序。
7、Spring Boot 如何实现异步?
回答提示:
- 常见方式:
@Async+ 执行器。 - 复杂编排:
CompletableFuture。 - 跨进程异步解耦:消息队列(Kafka/RabbitMQ),仍需处理投递、重试与幂等。
参考回答:
- 在配置类启用
@EnableAsync,将@Async方法放在 Spring 管理的 Bean 中。默认代理模式下,调用必须经过代理;同类中this.method()自调用不会触发异步拦截。 - Boot 3.5.x 在没有自定义
Executor时可自动配置执行器:常规情况下为ThreadPoolTaskExecutor;Java 21+ 且启用spring.threads.virtual.enabled=true时为使用虚拟线程的SimpleAsyncTaskExecutor。不能把“默认执行器”一概描述成新建线程或固定线程池。 - 业务任务可使用有明确名称的执行器,通过
@Async("业务执行器名")选择;传统线程池需按负载设置容量、队列和拒绝策略并监控堆积。虚拟线程也不免除数据库连接等下游资源的并发限制。 CompletableFuture是结果与编排抽象,是否换线程取决于具体方法及执行器;异常可经返回的 Future 获取,void异步方法的异常需通过AsyncUncaughtExceptionHandler等处理,调用方无法在提交处直接捕获任务内部异常。调用线程的事务上下文不会自动传播到异步线程。
参见官方 Framework 6.2 异步调用机制、Boot 3.5 执行器自动配置。
8、后端如何处理跨域?
- CORS(推荐):全局配置或
@CrossOrigin。 - 网关统一处理:在 API 网关层做跨域策略。
- 反向代理:由同一源地址同时提供前端和 API 代理入口,让浏览器发起同源请求;仅增加一个反向代理但浏览器仍访问不同源,并不能消除跨域限制。
CORS 是浏览器根据响应头决定是否允许脚本读取跨源响应的机制,不替代身份认证。需预检的请求会先发送 OPTIONS;使用 Spring Security 时应让 CORS 在安全认证前处理,避免无登录 Cookie 的预检被拒绝。携带凭据时,allowedOrigins 不能使用 "*",应设置可信的明确来源并按需启用 allowCredentials。网关与服务同时写 CORS 响应头也可能产生重复头,应统一策略。
参见官方 Framework 6.2 CORS、Spring Security CORS 集成。
9、面试高频追问:如何避免“只会背概念”?
可直接复述模板:
- 我们在项目里主要依赖 Spring Boot 自动配置提升交付速度,但关键配置会显式声明,避免隐式行为带来的排查成本。
- 异步能力统一接入线程池并做监控告警,避免任务堆积不可见。
- 跨域策略放在网关统一治理,服务内部只保留必要的细粒度配置。
