Spring 本身很好用,但是配置比较麻烦。
比如以前创建一个 Spring Web 项目,你要配很多东西:
Spring + Spring MVC + Tomcat + 数据库 + JSON + 各种 XML 配置……
Spring Boot 就像一个**“帮你把 Spring 项目快速组装起来的工具箱”**。
你只需要告诉它:
“我要做一个 Web 项目。”
它就根据你引入的依赖,自动帮你配置很多东西。
所以可以把 Spring Boot 理解成:
让 Spring 项目变得更容易创建、更容易配置、更容易运行。
Spring Boot 是基于 Spring Framework 的快速开发框架,核心目标是简化 Spring 应用的创建和配置。它通过 自动配置、Starter 依赖、嵌入式 Web 容器以及外部化配置 等机制,减少大量样板配置,使 Spring 应用能够快速启动和部署。
可以把 Spring Boot 启动想象成“开一家餐厅”。
第一步:
main()方法启动程序。
第二步:
Spring Boot 创建一个
SpringApplication。
第三步:
看看你这是普通 Java 程序、Web 程序还是响应式 Web 程序。
第四步:
创建 Spring 容器,也就是
ApplicationContext。
第五步:
加载配置文件、扫描 Bean、执行自动配置。
第六步:
如果是 Web 项目,就启动 Tomcat/Jetty 等服务器。
第七步:
执行
CommandLineRunner、ApplicationRunner。
最后:
发布
ApplicationReadyEvent,表示应用基本准备好了。
整个过程可以记成:
main()
↓
SpringApplication.run()
↓
读取配置
↓
创建 Spring 容器
↓
加载 Bean
↓
自动配置
↓
启动 Web 容器
↓
执行 Runner
↓
ApplicationReadyEvent
↓
项目启动完成
Spring Boot 官方文档也明确给出了启动事件的大体顺序:ApplicationStartingEvent → ApplicationEnvironmentPreparedEvent → ApplicationContextInitializedEvent → ApplicationPreparedEvent → ApplicationStartedEvent → Runner → ApplicationReadyEvent。(Home)
Spring Boot 的启动入口通常是
SpringApplication.run()。启动过程中首先创建并配置SpringApplication,准备Environment,然后根据应用类型创建对应的ApplicationContext。接着加载 Bean 定义并执行组件扫描和自动配置,通过refresh() 完成 Bean 初始化以及 WebServer 启动,之后执行ApplicationRunner 和CommandLineRunner,最后发布ApplicationReadyEvent,表示应用进入就绪状态。(Home)
你记住五个东西就行:
自动配置
Spring Boot 根据项目情况,自动帮你配置。
Starter
一组已经帮你打包好的依赖。
嵌入式 Web 容器
不需要自己装 Tomcat,也可以直接跑。
外部化配置
数据库地址、端口、Redis 地址等可以放配置文件或环境变量。
Actuator
帮你监控和管理项目。
所以一句话:
自动配、少配置、直接跑、方便改、方便监控。
Spring Boot 的核心特性主要包括 Auto Configuration 自动配置、Starter 起步依赖、Embedded Server 嵌入式容器、Externalized Configuration 外部化配置以及 Actuator 生产级监控管理能力。这些特性共同降低了 Spring 应用的配置和部署成本。(Home)
你写:
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
看起来只是调用了一行代码。
实际上这一行干了很多事情。
因为:
@SpringBootApplication
里面包含了:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
所以 Spring Boot 会:
扫描你的代码 → 自动配置 → 创建 Spring 容器 → 创建 Web 容器 → 启动服务器。
因此你执行:
java -jar xxx.jar
程序就能直接启动。
Spring Boot 通过
SpringApplication.run() 作为应用启动入口。@SpringBootApplication 是一个组合注解,包含@SpringBootConfiguration、@EnableAutoConfiguration 和@ComponentScan。对于 Servlet Web 应用,Spring Boot 会创建ServletWebServerApplicationContext,自动配置ServletWebServerFactory,通常启动嵌入式 Tomcat,并完成 Spring MVC 相关组件的初始化。(Home)
这是非常重要的一题。
假设你项目里面加入了:
spring-boot-starter-data-redis
Spring Boot 看到:
“哦,你项目要用 Redis。”
它就会尝试帮你创建:
RedisTemplate、连接工厂等相关 Bean。
但是它不是无脑创建。
比如:
你自己已经定义了一个 RedisTemplate。
Spring Boot 会说:
“你自己已经配了,那我就不抢你的。”
这就是自动配置。
核心思想:
你不配置,我帮你配置;你自己配置,我就让位。
Spring Boot 的自动配置主要通过
@EnableAutoConfiguration 实现。它根据 classpath 中存在的依赖以及当前 Spring 容器中的 Bean 和配置属性,选择相应的自动配置类,并通过各种@Conditional 条件进行判断,例如@ConditionalOnClass、@ConditionalOnMissingBean、@ConditionalOnProperty。如果用户已经提供了对应 Bean,自动配置通常会通过条件判断进行 back off,从而允许用户覆盖默认配置。(Home)
@EnableAutoConfiguration
↓
找到自动配置类
↓
Conditional 条件判断
↓
满足条件
↓
创建 Bean
最常见的是:
Tomcat
还有:
Jetty
如果是响应式 Web,也经常见到:
Netty
你可以理解成:
Spring Boot 自己背着一个“小型服务器”,所以不用把项目扔到外部 Tomcat 里面才能运行。
Servlet Web 应用中,Spring Boot 官方当前文档重点介绍嵌入式 Tomcat 和 Jetty;WebFlux 通常使用 Reactor Netty。(Home)
Spring Boot 支持嵌入式 Web 容器。对于 Servlet Web 应用,常见的是 Tomcat 和 Jetty;对于 Spring WebFlux,默认通常使用 Reactor Netty。通过 Starter 和自动配置可以自动创建对应的 WebServer。(Home)
本质上:
都是配置文件。
区别主要是写法不同。
.properties:
server.port=8080
spring.datasource.url=xxx
spring.datasource.username=root
.yml:
server:
port: 8080
spring:
datasource:
url: xxx
username: root
YAML 更适合:
配置很多、层级很多的项目。
application.properties 和application.yml 都可以用于 Spring Boot 外部化配置,功能上没有本质区别,主要区别是语法和可读性。Properties 使用key=value,YAML 通过缩进表达层级结构,更适合复杂配置。实际项目通常选择一种格式统一使用;如果同一位置同时存在.properties 和 YAML 配置,Spring Boot 会让.properties 优先。(Home)
比如我自己定义:
my:
name: 张三
age: 20
我要在 Java 里面拿出来。
最简单:
@Value("${my.name}")
private String name;
还有一种更适合大量配置的方式:
@ConfigurationProperties(prefix = "my")
可以理解为:
@Value适合拿一个值。
@ConfigurationProperties适合把一整组配置装进一个 Java 对象。
Spring Boot 支持多种方式读取自定义配置,常见的有
@Value、Environment 和@ConfigurationProperties。其中@Value 更适合少量配置项的注入,而@ConfigurationProperties 可以将具有相同前缀的配置批量绑定到 Java Bean,类型安全性和可维护性更好。(Home)
这个问题很容易背乱。
你只需要记住一个最核心的原则:
后来的覆盖前面的。
比如:
application.yml
↓
外部 application.yml
↓
环境变量
↓
命令行参数
通常越靠后的配置,优先级越高。
例如:
server.port=8080
配置文件说:
8080。
但是启动:
java -jar app.jar --server.port=9000
命令行说:
9000。
那么最后就是:
9000。
Spring Boot 官方当前的完整 PropertySource 顺序还包含默认属性、@PropertySource、Config Data、环境变量、Java System properties、JNDI、Servlet 参数、SPRING_APPLICATION_JSON、命令行参数以及测试专用属性等;命令行参数优先级高于文件配置。(Home)
Spring Boot 的配置采用
PropertySource 优先级机制,后加载的配置可以覆盖前面配置的同名属性。从实际开发最常见的角度来说,可以重点记住:配置文件中的默认配置可以被外部配置、环境变量以及命令行参数覆盖,其中命令行参数具有较高优先级。配置文件本身也存在 classpath 内配置和 jar 外配置的覆盖关系,profile-specific 配置会覆盖普通配置。(Home)
“application.yml 比 application.properties 优先级高。”
这个说法不准确。
普通 Jar 可以理解成:
“我只是把自己的 Java class 打包起来。”
Spring Boot Jar 则可以理解成:
“我把自己的代码 + 第三方依赖 + Spring Boot 启动器一起装进去了。”
例如:
my-app.jar
BOOT-INF/
├── classes/
│ └── 你的代码
│
└── lib/
├── spring.jar
├── jackson.jar
└── mysql.jar
所以你可以:
java -jar my-app.jar
直接运行。
Spring Boot 可执行 Jar 会使用 Boot Loader,并把应用类和依赖放入 BOOT-INF/classes、BOOT-INF/lib 等目录。(Home)
普通 Jar 主要用于 Java 类和资源的打包,本身不一定包含运行所需的全部依赖。Spring Boot 可执行 Jar 会通过
spring-boot-maven-plugin 或 Gradle Plugin 将应用类、依赖以及 Spring Boot Loader 打包到统一的可执行归档中,并通过java -jar 启动。其核心特点是支持嵌套 Jar,例如依赖位于BOOT-INF/lib,应用类位于BOOT-INF/classes。(Home)
当然可以。
Spring Boot 并不是:
“XML 禁止入场。”
只是现在更加推荐 Java 注解配置。
例如:
@ImportResource("classpath:application.xml")
就可以加载 XML。
所以:
可以用,只是不推荐把整个项目全部搞成 XML。
Spring Boot 支持 XML 配置,但官方更推荐使用 Java Configuration。对于已有 XML 配置的项目,可以通过
@ImportResource 将 XML 配置文件加载到 Spring 容器中,从而实现 XML 与 Java Configuration 混合使用。(Home)
这道题有个坑。
Spring Boot 没有一个统一的“最大请求数 = xxx”这种固定答案。
因为实际处理请求的是:
Tomcat / Jetty / Netty。
如果是传统 Spring MVC + Tomcat,那么默认情况下:
Tomcat worker threads 最大通常是 200。
所以很多面试题答案会说:
默认最大 200 个线程同时处理请求。
但这不等于:
“服务器最多只能有 200 个请求。”
例如当前 Tomcat 默认最大连接数是 8192,而工作线程默认最大 200。连接数和同时执行请求数不是一回事。(Home)
Spring Boot 本身并没有固定的最大并发请求数,具体取决于底层 Web Server 和线程模型。以 Spring MVC + Tomcat 为例,默认 worker thread 最大值通常为 200,因此在传统同步阻塞模型下,可以理解为默认最多约 200 个请求同时占用工作线程;另外 Tomcat 的最大连接数默认可以达到 8192,因此最大连接数、同时处理请求数和 QPS 是三个不同概念。(Home)
你面试时最好回答:
“没有固定的最大请求数。如果是默认 Tomcat,可以重点看
server.tomcat.threads.max ,默认 200。”
比直接说:
“Spring Boot 最大处理 200 个请求。”
专业很多。
Starter 就像:
“套餐。”
比如你想做 Web:
spring-boot-starter-web
它会帮你准备 Web 开发需要的一批依赖。
你不用一个一个找:
Spring MVC
Jackson
Tomcat
……
相当于:
我要吃 Web 套餐。
Starter:
好的,相关东西给你打包好了。
Starter 本质上是一组方便管理的依赖描述,它通过 Maven 或 Gradle 的传递依赖机制,将某一技术栈所需的相关依赖组合起来。例如
spring-boot-starter-web 用于快速引入 Spring Web 开发相关依赖。Starter 本身主要解决的是依赖管理和快速集成问题,自动配置则主要由 Spring Boot 的 Auto Configuration 机制负责,两者经常配合使用。(Home)
Starter ≠ 自动配置。
记住:
Starter
↓
帮你把依赖带进来
Auto Configuration
↓
根据依赖和条件帮你配置 Bean
假设:
前端:http://localhost:5173
后端:http://localhost:8080
虽然都是你自己的电脑,但是端口不同。
浏览器会认为:
“这两个不是一个来源。”
于是前端访问后端可能被浏览器拦截。
这就是跨域。
Spring 可以告诉浏览器:
“允许这个前端访问我。”
最常用:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:5173")
.allowedMethods("*");
}
}
Spring MVC 官方支持通过 WebMvcConfigurer#addCorsMappings 配置 CORS。(Home)
Spring Boot 中通常通过 Spring MVC 的 CORS 机制处理跨域,可以在
WebMvcConfigurer 中重写addCorsMappings(),配置允许的 Origin、Method、Header 以及是否允许携带 Cookie 等。对于前后端分离项目,也可以在网关层统一处理 CORS。
拦截器就像:
小区门卫。
用户请求进来:
请求
↓
门卫检查
↓
合格 → 放进去
不合格 → 拦下来
例如:
/token
没有登录:
不让访问。
所以可以用拦截器做:
登录检查、权限检查、日志记录等。
代码:
@Component
public class LoginInterceptor implements HandlerInterceptor {
}
然后:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
Spring MVC 官方就是通过 WebMvcConfigurer#addInterceptors 注册 HandlerInterceptor。(Home)
在 Spring Boot 中,我通常通过实现
HandlerInterceptor 编写拦截逻辑,然后通过WebMvcConfigurer#addInterceptors() 注册,并使用addPathPatterns() 和excludePathPatterns() 配置拦截及放行路径。常见应用场景包括登录认证、权限校验、请求日志和请求耗时统计等。(Home)
例如:
每天凌晨 2 点执行一次清理任务。
Spring Boot 可以使用:
@EnableScheduling
开启定时任务。
然后:
@Scheduled(cron = "0 0 2 * * ?")
public void clean() {
// ...
}
意思就是:
到时间自动执行。
Spring Boot 中可以使用 Spring Scheduling 实现定时任务。首先通过
@EnableScheduling 开启调度功能,然后在任务方法上使用@Scheduled,可以通过fixedRate、fixedDelay 或cron 指定执行策略。生产环境中还需要关注任务并发、线程池以及集群部署时的重复执行问题。(Home)
如果:
服务器 A
服务器 B
服务器 C
三个实例都有:
@Scheduled
那么默认情况下:
三个实例都可能执行。
所以集群定时任务通常还需要:
分布式锁 / XXL-JOB / Quartz 集群等。
Actuator 可以理解成:
给项目装了一套“仪表盘”。
它可以帮助你看:
项目活没活着?
数据库正常吗?
JVM怎么样?
内存怎么样?
有哪些 Bean?
有哪些配置?
例如:
/actuator/health
可以检查健康状态。
Spring Boot Actuator 是 Spring Boot 提供的生产级监控和管理模块,通过 Endpoint 暴露应用的健康状态、指标、环境信息、Bean 等运行信息。它能够辅助应用的监控、故障排查和运维管理。例如常见的
/actuator/health、/actuator/metrics 等端点。默认 Web Endpoint 基础路径通常是/actuator,具体暴露哪些端点可以进行配置。(Home)
你没必要把 1.x → 2.x 的所有变化全部背下来。
重点记三个:
Spring Boot 2.0 最低基线变成:
Java 8
而 1.x 时代还支持更老的 Java。(Home)
2.x 开始加入:
Spring WebFlux
也就是响应式 Web。
比如:
默认数据库连接池从 Tomcat Pool 切换到了 HikariCP。
同时 Actuator 等也进行了较大调整。(GitHub)
Spring Boot 2.x 相比 1.x 的主要变化包括:首先以 Java 8 作为最低基线;其次基于 Spring Framework 5 引入了对 Spring WebFlux 响应式编程的支持;另外默认数据库连接池切换为 HikariCP,Actuator、配置以及嵌入式 Web Server 等多个模块也进行了升级和调整。(Home)
1.x → 2.x
Java 8
WebFlux
HikariCP
生态升级
这道题非常重要。
最容易记:
Boot 2.x
↓
Boot 3.x
Spring Boot 3:
最低 Java 17。
(GitHub)
以前:
javax.servlet
javax.persistence
javax.validation
后来:
jakarta.servlet
jakarta.persistence
jakarta.validation
这是升级 Boot 3 时非常重要的兼容性变化。(GitHub)
Boot 3 基于:
Spring Framework 6
(GitHub)
如果项目使用 JPA:
Boot 3 默认使用 Hibernate 6 系列。
(GitHub)
Boot 3 对:
Observability
以及:
GraalVM Native Image
有更好的支持。(Home)
Spring Boot 3.x 相比 2.x 最大的升级点主要有几个:第一,最低 JDK 要求提升到 Java 17;第二,底层升级到 Spring Framework 6;第三,Java EE API 全面迁移到 Jakarta EE,因此大量
javax.* 包需要迁移到jakarta.*;第四,默认生态组件进行了升级,例如 Hibernate 6;另外 Boot 3 对 Observability、GraalVM Native Image 等现代部署和监控能力进行了增强。(Home)
Boot 3 最大的变化就是:Java 17、Spring 6、javax 改 jakarta,以及 Hibernate 6、可观测性和 Native Image 支持增强。
事件机制可以理解成:
一个人喊话,其他人自己决定要不要听。
比如:
用户注册成功
↓
发布“用户注册成功事件”
↓
邮件服务收到 → 发邮件
积分服务收到 → 加积分
优惠券服务收到 → 发优惠券
注册业务本身不用直接调用三个服务。
就相当于:
“我只负责宣布发生了什么,谁关心谁自己处理。”
Spring Boot 事件机制基于 Spring Framework 的
ApplicationEventPublisher 和事件监听器实现。业务代码通过发布事件实现生产者与消费者解耦,监听方可以通过@EventListener 或ApplicationListener 接收事件。Spring Boot 在启动过程中还会发布多个生命周期事件,例如ApplicationStartedEvent 和ApplicationReadyEvent。(Home)
比如一个项目有:
数据库 A:用户数据库
数据库 B:订单数据库
你不能只配置一个:
DataSource
而应该:
DataSource A
DataSource B
然后告诉程序:
这个业务去 A。
那个业务去 B。
一般通过:
@Qualifier
@Primary
区分。
如果是 MyBatis,还要进一步区分:
SqlSessionFactory、Mapper 扫描路径、事务管理器。
Spring Boot 多数据源的核心思路是定义多个
DataSource Bean,并分别绑定不同的配置前缀,再使用@Primary 和@Qualifier 解决默认数据源和依赖注入歧义。如果使用 MyBatis,还需要分别配置对应的SqlSessionFactory、SqlSessionTemplate 和 Mapper 扫描范围;如果涉及事务,还需要正确配置相应的数据源事务管理器。(Home)
正常情况下:
用户请求
↓
执行任务 A
↓
执行任务 B
↓
执行任务 C
↓
返回
如果 B 很慢,用户就要一直等。
异步就是:
用户请求
↓
任务 A
↓
把任务 B 扔到线程池
↓
继续往下执行
↓
返回
任务 B:
在线程池里自己慢慢干。
最常见的就是:
@EnableAsync
然后:
@Async
public void sendEmail() {
}
Spring Boot 中常用
@EnableAsync 开启异步执行能力,然后在方法上使用@Async,由 Spring 管理的TaskExecutor 在线程池中异步执行任务。实际项目中通常会自定义线程池,合理设置核心线程数、最大线程数、队列和拒绝策略,避免直接依赖默认线程池导致资源不可控。(Home)
有很多办法。
最常见可以记:
@PostConstructBean 创建完成之后执行。
@PostConstruct
public void init() {
}
理解:
“这个对象造好了,马上执行。”
CommandLineRunner项目启动过程中执行:
@Component
public class MyRunner implements CommandLineRunner {
@Override
public void run(String... args) {
}
}
ApplicationRunner和 CommandLineRunner 类似,只不过参数处理更方便。
ApplicationReadyEvent等整个应用准备完成之后:
@EventListener(ApplicationReadyEvent.class)
public void init() {
}
Spring Boot 启动阶段执行自定义代码有多种方式。Bean 初始化阶段可以使用
@PostConstruct;应用启动阶段可以使用CommandLineRunner 或ApplicationRunner;如果希望在应用基本完成启动、进入 Ready 状态后执行,可以监听ApplicationReadyEvent。其中CommandLineRunner 和ApplicationRunner 会在ApplicationStartedEvent 之后、ApplicationReadyEvent 之前执行。(Home)
“如果代码依赖整个应用已经启动完成,我更倾向于使用
ApplicationReadyEvent;如果只是启动阶段初始化任务,可以使用CommandLineRunner 或ApplicationRunner。”
其实不是:
@Autowired不能用。
而是:
不太推荐字段注入。
例如:
@Autowired
private UserService userService;
看起来简单,但有几个问题。
第一:
这个类需要什么依赖,不够明显。
第二:
字段不能方便地使用
final。
第三:
单元测试不方便。
推荐:
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
这样一看就知道:
这个 Controller 离不开 UserService。
Spring 官方也明确说明,如果 Bean 只有一个构造方法,可以直接使用该构造方法,不需要额外写 @Autowired。(Home)
并不是禁止使用
@Autowired,而是通常不推荐 字段注入。构造器注入具有依赖显式、支持final、便于单元测试以及更符合依赖不可变原则等优势。对于只有一个构造方法的 Bean,Spring 可以自动使用该构造方法,因此无需额外添加@Autowired。(Home)
不要回答:
“Spring Boot 不推荐
@Autowired。”
更准确的是:
不推荐字段注入,更推荐构造器注入。
因为:
@Autowired
public XxxService(UserService service) {}
本身就是构造器注入,也没有什么问题。
这是一个非常经典的坑。
最经典情况:
@Service
public class TestService {
public void a() {
b();
}
@Async
public void b() {
}
}
你以为:
a()
↓
b()
↓
异步
但实际上:
可能不会异步。
为什么?
因为 @Async 是靠 Spring AOP 代理实现的。
但是:
this.b();
是:
自己调用自己。
没有经过 Spring 代理。
所以 @Async 没机会拦截。
可以记:
异步要经过代理,自调用绕过代理。
另外,以下情况也可能有问题:
不是 Spring Bean
没有开启 @EnableAsync
方法/类不适合代理
调用方式绕过 Spring 代理
Spring 官方明确指出,@Async 默认采用 proxy 模式,因此同一个类内部的本地调用不会被代理拦截。(Home)
@Async 基于 Spring AOP Proxy 实现,因此调用必须经过 Spring 代理对象。常见失效场景包括同类内部自调用、对象没有交给 Spring 容器管理、没有开启 @EnableAsync ,以及某些方法或类无法被当前代理机制拦截。其中最典型的是 self-invocation,因为内部调用不会经过代理,所以异步拦截器不会生效。(Home)
@Async
↓
Spring AOP
↓
代理对象
↓
线程池
你这个需求非常简单。
比如数据库里面有:
商品分类
热门商品
系统字典
固定配置
项目启动之后:
Spring Boot 启动
↓
读取数据库
↓
拿到固定内容
↓
写入 Redis
↓
完成缓存预热
最常见的做法:
ApplicationReadyEvent+ RedisTemplate
例如:
@Component
public class CacheWarmup {
private final RedisTemplate<String, Object> redisTemplate;
public CacheWarmup(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@EventListener(ApplicationReadyEvent.class)
public void warmUp() {
// 1. 查询数据库
// 2. 写入 Redis
}
}
这样做的意思就是:
应用启动完成 → 从数据库加载固定数据 → 写进 Redis。
我会把这个过程称为 Redis 缓存预热。可以在 Spring Boot 启动阶段通过
ApplicationReadyEvent、CommandLineRunner 或ApplicationRunner 执行初始化逻辑,先从数据库查询需要预热的数据,再通过RedisTemplate 等客户端批量写入 Redis。生产环境还需要考虑幂等性、缓存 Key 设计、TTL、批量写入以及 Redis 不可用时的启动失败策略。(Home)
| 题目 | 你脑子里首先想到什么 |
|---|---|
| Spring Boot 是什么 | 让 Spring 更容易开发 |
| 启动流程 | main → run → 容器 → Bean → WebServer → Ready |
| 核心特性 | 自动配置 + Starter + 嵌入式容器 + 外部配置 + Actuator |
| main 怎么启动 Web | SpringApplication.run() |
| 自动配置 | 依赖 + 条件判断 + 自动创建 Bean |
| Web 容器 | Tomcat、Jetty、Netty |
| properties / yml | 都是配置,写法不同 |
| 自定义配置 | @Value/@ConfigurationProperties |
| 配置优先级 | 后面的覆盖前面的 |
| Boot Jar | 自己的代码 + 依赖 + Boot Loader |
| XML | 可以,@ImportResource |
| 最大请求数 | 没有固定值;Tomcat 默认 worker threads 200 |
| Starter | 依赖套餐 |
| CORS | 解决跨域 |
| Interceptor | 请求进来的门卫 |
| 定时任务 | @EnableScheduling + @Scheduled |
| Actuator | 监控/管理工具 |
| 1.x → 2.x | Java 8、WebFlux、HikariCP |
| 2.x → 3.x | Java 17、Spring 6、javax→jakarta、Hibernate 6 |
| 事件 | 发布者和监听者解耦 |
| 多数据源 | 多个 DataSource + Qualifier/Primary |
| 异步 | @EnableAsync + @Async + 线程池 |
| 启动执行代码 | @PostConstruct / Runner / ReadyEvent |
| @Autowired | 不是不能用,是不推荐字段注入 |
| @Async 失效 | 最经典:同类自调用绕过代理 |
| Redis 启动缓存 | 缓存预热 |
按照 Java 后端面试的实际追问习惯,我建议你把下面 8 道背得最熟:
① 自动配置
@EnableAutoConfiguration
↓
找到自动配置类
↓
@Conditional 判断
↓
满足条件
↓
创建 Bean
② Spring Boot 启动流程
main
↓
SpringApplication.run()
↓
Environment
↓
ApplicationContext
↓
Bean + AutoConfiguration
↓
WebServer
↓
Runner
↓
ApplicationReadyEvent
③ Starter 和自动配置区别
Starter
= 帮你引入依赖
AutoConfiguration
= 帮你配置 Bean
④ 最大请求数
不要死背:
“200。”
要背:
“Spring Boot 没有统一固定值。传统 Spring MVC + Tomcat 默认 worker threads 是 200,连接数是另外一个概念。”
⑤ Boot 2 → Boot 3
直接背:
Java 17 + Spring 6 + javax → jakarta + Hibernate 6 + Native/Observability 增强。
⑥ @Autowired
直接说:
“不是不推荐
@Autowired ,而是不推荐字段注入,更推荐构造器注入。”
⑦ @Async 失效
直接说:
**“**
@Async 基于 Spring AOP 代理,同类内部自调用没有经过代理,所以异步不会生效。”
⑧ Redis 启动缓存
直接说:
“这是缓存预热,可以监听
ApplicationReadyEvent ,启动完成后查询数据库,再批量写入 Redis。”
这些答案已经足够覆盖大多数初中级 Java/Spring Boot 面试中的第一轮问答,而且可以继续向 Spring、AOP、线程池、Redis、MySQL 方向展开。