Spring Boot 面试题笔记

Spring Boot 面试题笔记

个人复习笔记,覆盖 Spring Boot 自动配置、配置管理、Starter、部署运维的高频面试题。

目录


Spring Boot 基础认知

Spring Boot 解决了 Spring 的哪些痛点?

  1. 配置繁琐 → 自动配置(AutoConfiguration),按约定默认配好,需要时再覆盖;
  2. 依赖管理痛苦 → Starter 起步依赖 + parent 统一版本,不再为依赖冲突头疼;
  3. 部署麻烦 → 内嵌 Tomcat/Jetty/Undertow,打成可执行 jar 直接 java -jar 启动,不用外置容器;
  4. 生产级功能缺失 → Actuator 提供健康检查、指标、监控端点。

一句话:约定优于配置,让开发者专注业务。

@SpringBootApplication 包含哪三个注解?各有什么作用?(高频)

java 复制代码
@SpringBootApplication
    ├── @SpringBootConfiguration   // 本质是 @Configuration,标识配置类
    ├── @EnableAutoConfiguration   // 开启自动装配(核心)
    └── @ComponentScan             // 扫描当前包及子包的组件

这也解释了为什么启动类要放在根包:@ComponentScan 默认扫启动类所在包及子包。


自动配置原理

自动配置的实现原理?(最高频)

按 Spring Boot 2.7+/3.x 的链路回答(2.7 以前文件名不同,原理一致):

  1. @SpringBootApplication 上的 @EnableAutoConfiguration 引入 @Import(AutoConfigurationImportSelector.class);
  2. AutoConfigurationImportSelector 从所有依赖 jar 包的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件里读出全部候选自动配置类(旧版本读 META-INF/spring.factories);
  3. 每个 XxxAutoConfiguration 类上大量使用条件注解 (@ConditionalOnClass、@ConditionalOnMissingBean、@ConditionalOnProperty 等)按条件筛选:类路径有这个类、用户没自己配、配置开关打开......满足条件的才生效;
  4. 生效的配置类通过 @Bean 向容器注入默认组件(如 DataSource、RedisTemplate),用户自己定义的同类型 Bean 优先(@ConditionalOnMissingBean 让位)。

一句话总结:启动时按类路径扫描自动配置清单,再用条件注解过滤,把符合约定的 Bean 自动注册进容器。

常见的 @Conditional 条件注解有哪些?

注解 生效条件
@ConditionalOnClass 类路径存在指定类
@ConditionalOnMissingClass 类路径不存在指定类
@ConditionalOnBean 容器中存在指定 Bean
@ConditionalOnMissingBean 容器中不存在指定 Bean(用户自定义优先的关键)
@ConditionalOnProperty 配置属性满足条件(如 havingValue)
@ConditionalOnWebApplication 是 Web 应用
@ConditionalOnResource 类路径存在指定资源文件

如何排查某个自动配置类为什么没生效?

启动加 --debug(或配置 debug=true),启动日志输出 ConditionEvaluationReport:Positive matches(生效了,命中哪个条件)和 Negative matches(没生效,差哪个条件)。

如何排除某个自动配置?

java 复制代码
// 方式一:注解排除
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)

// 方式二:配置文件排除
// spring.autoconfigure.exclude=xxx.XxxAutoConfiguration

配置管理

配置文件的加载优先级?

从高到低(高优先级覆盖低优先级):

  1. 命令行参数 --server.port=8081
  2. JNDI / Java 系统属性 / 操作系统环境变量
  3. jar 包外部的 application-{profile}.yml → application.yml
  4. jar 包内部的 application-{profile}.yml → application.yml

同目录下 properties 优先于 yml。外部配置优于内部,所以线上改外置配置即可,不用重新打包。

@Value 和 @ConfigurationProperties 的区别?

@Value @ConfigurationProperties
使用方式 一个个字段标 整个类批量绑定前缀
松散绑定 不支持(严格匹配) 支持(my.name 可绑到 myName)
SpEL 支持 不支持
JSR303 校验 不方便 支持 @Validated + @NotBlank 等
适用场景 少量单个配置 一组相关配置(如整个邮件配置段)
java 复制代码
@Component
@ConfigurationProperties(prefix = "mail")
@Validated
public class MailProperties {
    private String host;
    private Integer port;
    // getter/setter
}

多环境怎么配置?

yaml 复制代码
spring:
  profiles:
    active: dev        # 默认激活 dev

---                    # yml 中用 --- 分割文档块
spring:
  config:
    activate:
      on-profile: dev
server:
  port: 8080
---
spring:
  config:
    activate:
      on-profile: prod
server:
  port: 80

启动时切换:java -jar app.jar --spring.profiles.active=prod。不同环境用 application-dev.yml / application-prod.yml 拆文件。

配置里的敏感信息(数据库密码)怎么处理?

  1. Jasypt 加密后存配置,启动时传解密密钥;
  2. 环境变量 / 启动参数注入;
  3. 用 Nacos/Apollo 等配置中心统一管理。

Starter 起步依赖

什么是 Starter?

一组依赖描述符 (pom 聚合)+ 自动配置 的封装。引入 spring-boot-starter-web 就等于引入了 web 开发所需的一整套依赖(Spring MVC、Jackson、内嵌 Tomcat),并自动完成配置,无需逐个声明版本。

命名约定:官方 starter 叫 spring-boot-starter-xxx;自定义的叫 xxx-spring-boot-starter。

如何自定义一个 Starter?(高频)

  1. 建两个模块(或一个):
    • xxx-spring-boot-autoconfigure:写自动配置类;
    • xxx-spring-boot-starter:空工程,聚合依赖;
  2. 写核心服务类 + 配置属性类(@ConfigurationProperties);
  3. 写自动配置类,用条件注解控制生效:
java 复制代码
@AutoConfiguration
@ConditionalOnClass(SmsService.class)
@ConditionalOnProperty(prefix = "sms", name = "enabled", havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties(SmsProperties.class)
public class SmsAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public SmsService smsService(SmsProperties props) {
        return new SmsService(props);
    }
}
  1. 在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(旧版 spring.factories)里登记该配置类;
  2. 其他项目引入 starter,配好 sms.* 配置即可直接注入 SmsService。

Web 开发相关

Spring Boot 的启动流程?

  1. SpringApplication.run() → 创建 SpringApplication 实例(推断应用类型、加载初始化器和监听器);
  2. 准备 Environment(加载配置文件、环境变量);
  3. 创建并刷新 ApplicationContext(核心在 refresh():加载 BeanDefinition、执行 BeanFactoryPostProcessor、自动配置导入、实例化单例 Bean、启动 Web 服务器);
  4. 执行 ApplicationRunner / CommandLineRunner 回调;
  5. 发布启动完成事件,应用就绪。

Spring Boot 内嵌 Tomcat 是怎么启动的?

Servlet 容器不再以 war 包形式独立部署,而是作为应用里的一个对象:ServletWebServerFactoryAutoConfiguration 自动配置 TomcatServletWebServerFactory,容器刷新过程中调用其 getWebServer() 启动内嵌 Tomcat,并把 DispatcherServlet 注册进去。想换容器引入 spring-boot-starter-jetty/undertow、排除默认 tomcat 即可。

跨域怎么解决?

java 复制代码
// 方式一:全局配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowedMethods("*")
                .allowCredentials(true);
    }
}

// 方式二:@CrossOrigin 标在类/方法上
// 方式三:交给网关统一处理(微服务推荐)

接口参数校验怎么做?

spring-boot-starter-validation + JSR303 注解(@NotNull、@NotBlank、@Min、@Pattern 等),Controller 参数上加 @Valid / @Validated,配合全局异常处理器捕获 MethodArgumentNotValidException 返回友好提示。


部署与运维

Actuator 是什么?常用端点有哪些?

生产级监控端点集合,默认暴露部分端点,需在配置中放开:

端点 作用
/health 健康检查(数据库、Redis 连通性聚合展示),配合 K8s 探针
/info 应用信息
/metrics JVM、HTTP、系统各项指标
/env 环境与配置属性(注意脱敏)
/beans 容器中所有 Bean
/loggers 运行时动态调整日志级别
/threaddump、/heapdump 线程/堆快照排查问题
yaml 复制代码
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics

生产上常配合 Spring Boot Admin 或 Prometheus + Grafana 做可视化监控。

优雅停机怎么配置?

yaml 复制代码
server:
  shutdown: graceful        # 2.3+ 支持
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s

效果:收到 kill 信号后不再接收新请求,等待存量请求处理完(或超时)再关闭容器,避免请求被硬切断。K8s 场景配合 preStop 钩子。

Spring Boot 打的是 jar,为什么能直接 java -jar 运行?

Spring Boot Maven/Gradle 插件打成可执行 fat jar :依赖的第三方 jar 全部放进 BOOT-INF/lib,应用类在 BOOT-INF/classes,由自定义的 JarLauncher + 自定义 URL 协议(jar:nested:)加载。区别于普通 jar 的地方在于 MANIFEST 里 Main-Class 指向 Launcher 而不是业务类。


版本与生态

Spring Boot 2.x 和 3.x 的主要区别?

  1. JDK 基线 :3.x 要求 Java 17+(2.x 是 Java 8+);
  2. Jakarta EE :包名从 javax.* 迁移到 jakarta.*(如 javax.servlet → jakarta.servlet),老代码升级要改 import;
  3. Spring Framework 5 → 6,支持 AOT / GraalVM Native Image;
  4. 可观测性增强:原生集成 Micrometer Tracing(替代 Sleuth);
  5. 自动配置登记文件从 spring.factories(2.7 弃用)变为 AutoConfiguration.imports。

Spring Boot 和 Spring Cloud 的关系?

Spring Boot 是地基 (快速构建单个应用);Spring Cloud 是微服务全家桶(注册中心、配置中心、网关、熔断限流等),基于 Boot 的自动配置体系把各微服务组件整合起来。版本上有对应关系(Boot 3.x 配 Spring Cloud 2023.x/2024.x)。

Spring Boot 里 Bean 的默认初始化时机?想懒加载怎么办?

默认启动即实例化 所有单例 Bean(预实例化);需要懒加载可在 Bean/配置类/启动类上标 @Lazy,或全局配置 spring.main.lazy-initialization=true(一般不全局开,会把问题推迟到运行期)。

相关推荐
Azure++9 小时前
MyBatis 面试题笔记
个人笔记
Azure++13 小时前
JVM 面试题笔记
个人笔记
我的golang之路果然有问题9 个月前
linux 个人笔记导出之网络,防火墙,定时,权限,后台
linux·运维·服务器·网络·笔记·个人笔记
我的golang之路果然有问题9 个月前
mysql 个人笔记导出之-数据库时间戳问题以及增删改查
数据库·笔记·学习·mysql·分享·个人笔记