Spring Boot 高频面试题汇总

5 阅读5分钟

Spring Boot 高频面试题汇总

第一部分:基础入门

Q1:@SpringBootApplication 注解做了什么?

参考答案

@SpringBootApplication 是一个组合注解,包含三个核心注解:

@SpringBootApplication
// 等价于
@Configuration     // 标记为配置类
@EnableAutoConfiguration  // 启用自动配置
@ComponentScan           // 组件扫描(默认扫描同包及子包)

@EnableAutoConfiguration 内部:

@AutoConfigurationPackage  // 记录主类所在包
@Import(AutoConfigurationImportSelector.class)  // 导入自动配置类

Q2:自动配置原理?

参考答案

  1. @EnableAutoConfiguration 通过 @Import 导入 AutoConfigurationImportSelector

  2. selectImports() 方法执行流程:

    // 1. 从 spring.factories 读取所有候选配置
    List<String> configurations = SpringFactoriesLoader
        .loadFactoryNames(EnableAutoConfiguration.class, classLoader);
    
    // 2. 根据 @Conditional 条件过滤
    configurations = configurations.stream()
        .filter(ConfigurationClassFilter.filter())
        .collect(Collectors.toList());
    
    // 3. 按需配置
    return configurations.toArray(new String[0]);
    
  3. 按需配置:Spring Boot 只加载符合条件的配置类


Q3:Spring Boot 和 Spring MVC 的区别?

参考答案

维度Spring MVCSpring Boot
定位Web 框架应用框架
配置XML/注解配置自动配置
依赖手动管理起步依赖
部署WAR 到 TomcatJAR 内嵌容器
监控Actuator

第二部分:核心机制

Q4:IoC 和 DI 的区别?

参考答案

概念说明
IoC(控制反转)将对象创建/管理权交给容器
DI(依赖注入)容器在运行时注入依赖

DI 是实现 IoC 的一种方式

// 传统:自己创建
class UserService {
    private UserRepository repo = new UserRepositoryImpl(); // 主动控制
}

// IoC/DI:容器注入
class UserService {
    private UserRepository repo;  // 被动接收
    UserService(UserRepository repo) { this.repo = repo; }
}

Q5:Bean 的生命周期?

参考答案

1. 实例化 → new 对象
      ↓
2. 属性赋值 → setXxx()
      ↓
3. BeanNameAware → setBeanName()
      ↓
4. BeanFactoryAware → setBeanFactory()
      ↓
5. ApplicationContextAware → setApplicationContext()
      ↓
6. BeanPostProcessor.postProcessBeforeInitialization()
      ↓
7. @PostConstruct → 初始化方法
      ↓
8. InitializingBean.afterPropertiesSet()
      ↓
9. 自定义 init-method
      ↓
10. BeanPostProcessor.postProcessAfterInitialization()
      ↓
11. Bean 就绪
      ↓
12. @PreDestroy → 销毁前回调
      ↓
13. DisposableBean.destroy()
      ↓
14. 自定义 destroy-method

Q6:Spring AOP 的代理机制?

参考答案

代理方式条件原理
JDK 动态代理目标类实现接口Proxy.newProxyInstance
CGLIB 代理未实现接口/配置强制使用继承目标类生成子类
// 代理对象调用流程
proxy.save();  // 调用
    ↓
JdkDynamicAopProxy.invoke()  // 拦截
    ↓
MethodInterceptor.before()
    ↓
target.save();  // 目标方法
    ↓
MethodInterceptor.after()

Spring Boot 2.x 默认使用 CGLIB


Q7:@Transactional 失效场景?

参考答案

场景原因解决
private 方法AOP 不支持改为 public
自调用不走代理注入自身代理
异常被 catch异常未抛出重新抛出
非 RuntimeException默认只回滚 RuntimerollbackFor 指定
非 Spring 管理的 Bean没有代理@Service 管理
多数据源事务管理器未指定指定 transactionManager

Q8:循环依赖如何解决?

参考答案

Spring 处理循环依赖的三级缓存

// 一级缓存:成品 Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

// 二级缓存:提前曝光的 Bean(未完成属性注入)
private final Map<String, Object> earlySingletonObjects = new HashMap<>();

// 三级缓存:Bean 工厂(用于创建代理)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

解决流程

A 创建 → 需要 B → 去拿 B
B 创建 → 需要 A → 去拿 A
A 已创建(半成品) → 返回 A
B 完成 → 返回 A
A 完成

无法解决的场景

  • 构造器循环依赖
  • prototype 作用域循环依赖

第三部分:Web 开发

Q9:GET 和 POST 的区别?

参考答案

维度GETPOST
参数位置URLBody
长度限制~2KB
缓存可缓存不缓存
幂等幂等非幂等
安全性参数暴露相对安全

Q10:拦截器和过滤器的区别?

参考答案

维度FilterInterceptor
来源Servlet APISpring MVC
执行位置DispatcherServlet 前Controller 前
作用范围所有请求Controller 层
获取 Spring Bean
典型场景字符编码、CORS认证、日志

Q11:异常处理流程?

参考答案

Controller 抛出异常
        ↓
DispatcherServlet 捕获
        ↓
HandlerExceptionResolver 处理
        ↓
@ExceptionHandler 方法
        ↓
返回错误响应

第四部分:数据访问

Q12:MyBatis #{} 和 ${} 的区别?

参考答案

特性#{}${}
SQL预编译参数占位字符串拼接
注入防注入可能注入
类型自动转换直接替换

Q13:Redis 缓存一致性问题?

参考答案

Cache Aside 模式

// 读
Cache cache = redis.get(key);
if (cache == null) {
    cache = db.get(key);
    redis.set(key, cache);
}

// 写
db.update(key, value);
redis.delete(key);  // 删除缓存,不是更新

延迟双删

redis.delete(key);
db.update(key, value);
Thread.sleep(100);
redis.delete(key);  // 延迟再删

Q14:如何解决缓存穿透、击穿、雪崩?

参考答案

问题解决方案
穿透布隆过滤器 / 空值缓存
击穿分布式锁 / 热点数据永不过期
雪崩过期时间随机 / 多级缓存

第五部分:微服务

Q15:Nacos AP 和 CP 切换?

参考答案

# 切换为 CP 模式
curl -X PUT 'http://localhost:8848/nacos/v1/ns/operator/mode?mode=CP'

# 切换为 AP 模式
curl -X PUT 'http://localhost:8848/nacos/v1/ns/operator/mode?mode=AP'

选择建议

  • 服务注册发现 → AP(高可用)
  • 配置管理 → CP(强一致)

Q16:Sentinel 和 Hystrix 的区别?

参考答案

维度SentinelHystrix
隔离策略信号量线程池
熔断触发慢调用/异常比例异常数/超时
规则动态推送配置后不可变
状态活跃停止维护

第六部分:综合问题

Q17:Spring Boot 启动流程?

参考答案

SpringApplication.run()
        ↓
prepareEnvironment()  // 准备环境createApplicationContext()  // 创建上下文prepareContext()  // 预处理上下文refreshContext()  // 刷新上下文
        ↓
  └→ onRefresh() → DispatcherServlet 初始化
        ↓
afterRefresh()  // 刷新后处理started()  // 发布 ApplicationStartedEventcallRunners()  // 执行 ApplicationRunner

Q18:如何排查 Spring Boot 启动失败?

参考答案

  1. 查看错误日志:重点关注 Caused by
  2. 检查端口占用netstat -ano | grep 8080
  3. 检查依赖冲突mvn dependency:tree
  4. 检查配置:application.yml 是否正确
  5. 启用调试日志
    logging:
      level:
        org.springframework: DEBUG
    
  6. 检查自动配置报告
    debug: true
    

Q19:Spring Boot 2.x 和 3.x 的区别?

参考答案

维度Spring Boot 2.xSpring Boot 3.x
Java 版本8+17+
Jakarta EEJava EE 8Jakarta EE 9+
注解包名javax.*jakarta.*
最低 Spring5.x6.x
建议保守迁移新项目

迁移注意

  • 依赖升级到支持 jakarta 的版本
  • 注解从 javax 改为 jakarta
  • 不兼容的库需要替换

Q20:如何设计一个好的微服务架构?

参考答案

设计原则

  1. 单一职责:每个服务只做一件事
  2. 松耦合:服务间通过接口通信
  3. 高内聚:相关功能放在一起
  4. 独立部署:服务可独立部署升级

核心组件

├── 网关层     → Gateway、Zuul
├── 注册中心   → Nacos、Eureka
├── 配置中心   → Nacos Config、Apollo
├── 服务调用   → OpenFeign、Dubbo
├── 限流熔断   → Sentinel、Hystrix
├── 链路追踪   → Sleuth、Zipkin
├── 日志监控   → ELK
└── 服务容器   → Docker、K8s

📝 面试题持续更新中,欢迎补充!