Skip to content

SpringBoot2核心功能面试题库 ​

生成时间:2026-05-21 22:21


【面试题】1. SpringBoot自动配置的完整触发链路是怎样的?从启动类注解到最终Bean注册,说清楚每一步。 ​

【标准答案】整个链路分四步走。第一步,@SpringBootApplication是一个组合注解,里面包含了@EnableAutoConfiguration,而@EnableAutoConfiguration上标注了@Import(AutoConfigurationImportSelector.class)。第二步,AutoConfigurationImportSelector的selectImports方法会调用SpringFactoriesLoader,去扫描所有jar包下META-INF/spring.factories文件中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置类全限定名列表(SpringBoot2.7+还会读META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件)。第三步,拿到的这些自动配置类并不是全部生效,每一个配置类上都有一堆条件注解做过滤,比如@ConditionalOnClass检查类路径是否存在某个类、@ConditionalOnMissingBean检查容器中是否缺少某个Bean、@ConditionalOnProperty检查配置文件中的属性值,只有所有条件都满足,这个配置类才会被解析。第四步,满足条件的配置类被解析为BeanDefinition,注册到BeanDefinitionRegistry中,后续由IoC容器走正常的实例化流程创建Bean。面试的时候关键要说清"扫描→过滤→注册"这三段式,条件注解是核心过滤机制,这就是为什么引入了starter的依赖但没配数据源也不会报错——DataSourceAutoConfiguration上有@ConditionalOnClass和@ConditionalOnMissingBean守着。

【面试题】2. @ConfigurationProperties绑定中,松散绑定的规则有哪些?在配置文件中哪些写法能绑定到Java的myFirstName字段? ​

【标准答案】松散绑定是SpringBoot对配置属性名和Java字段名不一致的兼容机制,主要支持四种规则:一是驼峰转横杠,myFirstName对应my-first-name;二是全小写加下划线,对应my_first_name;三是全大写下划线(环境变量风格),对应MY_FIRST_NAME;四是全小写无分隔符,对应myfirstname。实际开发中最常用的就是横杠风格my-first-name和下划线风格my_first_name。但要注意一个重要限制:松散绑定只适用于@ConfigurationProperties的属性映射阶段,在@Value注解中是严格匹配的,@Value("${my-first-name}")不会自动映射到myFirstName字段,必须写精确的key。另外,对于Map类型的属性,key中的横杠不会被转换,因为它本身就是key的一部分。面试中加分点:提到@Value不支持松散绑定,以及Map的key是例外。

【面试题】3. BeanFactory和ApplicationContext有什么区别?SpringBoot中默认用的是哪个? ​

【标准答案】BeanFactory是Spring最底层的容器接口,只提供最基本的IoC功能——getBean、类型查询等,它采用懒加载策略,Bean在首次获取时才创建。ApplicationContext是BeanFactory的子接口,在基础功能上扩展了国际化(MessageSource)、资源加载(ResourceLoader)、事件发布(ApplicationEventPublisher)、环境抽象(Environment)、AOP集成等能力,并且默认预加载所有单例Bean。SpringBoot默认使用的是AnnotationConfigServletWebServerApplicationContext,它继承自ApplicationContext体系。面试时的关键区分点:BeanFactory是"最基本的容器",ApplicationContext是"增强版容器",SpringBoot不会直接用BeanFactory。但有个细节——ApplicationContext内部持有一个DefaultListableBeanFactory实例作为实际的Bean工厂,所以ApplicationContext更像是一个门面(Facade),底层Bean管理仍然委托给BeanFactory。如果你在Bean中实现BeanFactoryAware接口拿到的也是内部的那个BeanFactory实例。

【面试题】4. BeanPostProcessor和BeanFactoryPostProcessor的区别和使用场景是什么? ​

【标准答案】这是两个不同阶段的后置处理器。BeanFactoryPostProcessor在BeanDefinition注册完成后、Bean实例化之前执行,它操作的是BeanDefinition级别的元数据,典型场景是修改Bean的属性值、改变作用域等,比如PropertySourcesPlaceholderConfigurer就是BeanFactoryPostProcessor,负责把${}占位符替换为实际值。BeanPostProcessor在Bean实例化之后执行,分beforeInitialization和afterInitialization两个回调,分别在初始化方法(@PostConstruct、InitializingBean.afterPropertiesSet)前后执行,它操作的是Bean实例本身,典型场景是AOP代理创建——AbstractAutoProxyCreator就是BeanPostProcessor,在afterInitialization中把目标对象包装成代理对象返回。执行顺序:BeanFactoryPostProcessor → Bean实例化 → BeanPostProcessor.beforeInitialization → @PostConstruct/InitializingBean → BeanPostProcessor.afterInitialization。面试加分:说到BeanFactoryPostProcessor可以注册新的BeanDefinition,而BeanPostProcessor可以替换返回的Bean对象(代理就是替换)。

【面试题】5. @Import的三种用法分别是什么?自定义Starter时一般用哪种? ​

【标准答案】@Import有三种用法。第一种:直接导入普通配置类,@Import(DataSourceConfig.class),效果等价于在配置类上标@Component但不用包扫描就能注册。第二种:导入ImportSelector实现类,@Import(MyImportSelector.class),在selectImports方法中返回要导入的配置类全限定名数组,适合根据条件动态选择导入哪些配置。第三种:导入ImportBeanDefinitionRegistrar实现类,@Import(MyRegistrar.class),直接操作BeanDefinitionRegistry手动注册BeanDefinition,是最灵活的方式,可以控制Bean的名称、角色等元数据。自定义Starter开发中,最常见的是在自动配置类上标注@Import直接导入功能配置类,或者配合AutoConfigurationImportSelector通过spring.factories机制间接选择导入。但如果Starter需要根据条件动态注册Bean或需要精细控制BeanDefinition,就会用ImportBeanDefinitionRegistrar。面试加分:说到SpringBoot自动配置底层用的是第二种——AutoConfigurationImportSelector就是ImportSelector的实现。

【面试题】6. AOP中五种通知类型的执行顺序是什么?同一个切点有多个切面时如何控制优先级? ​

【标准答案】五种通知类型的执行顺序:正常情况下是Around前置→Before→目标方法→Around后置→AfterReturning→After(After总会执行,相当于finally)。异常情况下是Around前置→Before→目标方法抛异常→AfterThrowing→After,Around后置和AfterReturning不执行。Around是最强大的,它能决定是否执行目标方法、修改参数、修改返回值、捕获异常,相当于其他四种通知的超集。多个切面作用在同一切点时,通过@Order注解或实现Ordered接口控制优先级,数值越小优先级越高。优先级高的切面的Around前置和Before先执行,但AfterReturning/After/AfterThrowing后执行,形成洋葱模型——先进后出。面试关键:说清洋葱模型的嵌套结构,@Order值小的切面是外层洋葱,先进入后退出。还有一个细节——Spring5.2.7+对同一个切面内同一切点的多个通知方法做了排序调整,Before和AfterReturning的执行顺序跟定义顺序一致了,但跨切面仍然是洋葱模型。

【面试题】7. SpringBoot的事件机制是怎样的?内置的核心事件有哪些?分别在什么时候触发? ​

【标准答案】SpringBoot事件机制基于Spring的事件发布订阅模型,核心三要素:ApplicationEvent(事件对象)、ApplicationEventPublisher(发布者,ApplicationContext本身就是)、ApplicationListener/@EventListener(监听者)。发布事件调用ApplicationContext.publishEvent(),同步事件在发布线程执行,加@Async后异步执行。内置核心事件按启动顺序:ApplicationStartingEvent——应用刚启动、还没做任何处理时;ApplicationEnvironmentPreparedEvent——Environment准备好但上下文未创建;ApplicationContextInitializedEvent——上下文已创建并初始化、Bean定义未加载;ApplicationPreparedEvent——Bean定义已加载但未刷新;ContextRefreshedEvent——上下文刷新完成,所有单例Bean已创建(这个是Spring原生事件);ApplicationStartedEvent——上下文刷新后、CommandLineRunner执行前;ApplicationReadyEvent——应用完全就绪,可以接收请求;ContextClosedEvent——上下文关闭时。面试加分点:ContextRefreshedEvent在SpringMVC场景可能触发两次(Root和Child容器各刷新一次),ApplicationReadyEvent才是真正"可以用了"的信号,做健康检查要用这个。

【面试题】8. SpringBoot如何切换嵌入式容器?Tomcat、Undertow、Jetty各自的适用场景是什么? ​

【标准答案】切换容器就是换starter依赖。默认是spring-boot-starter-web,它内含spring-boot-starter-tomcat。要换Undertow,先排除tomcat依赖,再引入spring-boot-starter-undertow;换Jetty同理,引入spring-boot-starter-jetty。适用场景:Tomcat是默认选择,生态最成熟、资料最多、稳定性经过大规模验证,绝大多数场景够用;Undertow是JBoss出品的,基于NIO,内存占用更小、高并发轻量级场景表现优秀,适合微服务和对资源敏感的容器化部署;Jetty对长连接和WebSocket支持更好,历史上常用于异步和实时通信场景,但社区活跃度不如前两者。调优方面,server.tomcat/max-threads、server.undertow/io-threads、server.jetty/max-threads等参数可以调整线程模型。面试加分:说Undertow默认不创建JSP引擎所以不支持JSP(现在基本不用JSP了),以及容器切换的本质是ServletWebServerFactory接口的不同实现类,自动配置类根据classpath下存在的类来决定激活哪个。

【面试题】9. @Transactional的传播行为有哪些?实际开发中最常用的是哪几个?举一个需要用REQUIRES_NEW的场景。 ​

【标准答案】7种传播行为:REQUIRED(默认,有事务加入、没有新建)、SUPPORTS(有事务加入、没有非事务执行)、MANDATORY(必须在事务中、否则抛异常)、REQUIRES_NEW(总是新建事务、挂起当前事务)、NOT_SUPPORTED(非事务执行、挂起当前事务)、NEVER(必须非事务、否则抛异常)、NESTED(有事务则嵌套执行、没有新建)。实际开发中90%以上用的是REQUIRED,这是默认值不用显式指定。其次是REQUIRES_NEW,典型场景:操作日志记录。比如主业务方法有事务,主业务失败要回滚,但操作日志不能回滚,这时候日志记录方法标注propagation=REQUIRES_NEW,它会挂起主事务、开一个独立的新事务,主事务回滚不影响日志入库。再比如扣款流水记录,扣款失败回滚但流水必须留下。NESTED用得少但面试常问——它在已有事务中创建savepoint,内层回滚只回到savepoint不影响外层,但外层回滚会连带内层一起回滚,这是和REQUIRES_NEW的关键区别。

【面试题】10. SpringBoot Actuator的/health端点是如何工作的?如何自定义HealthIndicator? ​

【标准答案】/health端点由HealthEndpoint类暴露,它聚合所有HealthIndicator的实现,每个HealthIndicator负责检查一项组件的健康状态,比如DataSourceHealthIndicator检查数据库连接、DiskSpaceHealthIndicator检查磁盘空间、RedisHealthIndicator检查Redis连接。最终结果按状态严重程度汇总:DOWN > OUT_OF_SERVICE > UP > UNKNOWN,只要有一个DOWN,整体状态就是DOWN。自定义HealthIndicator很简单:实现HealthIndicator接口,在health()方法中做检查逻辑,返回Health.up().withDetail("key","value").build()或Health.down().withDetail("error","msg").build(),类上标注@Component让Spring扫描到即可。端点安全暴露策略:management.endpoints.web.exposure.include指定要暴露的端点,默认只暴露/health和/info,生产环境需要显式配置;management.endpoint.health.show-details控制健康详情的显示策略(never/when-authorized/always)。面试加分:提到2.x后Actuator端点统一用/actuator前缀,端口可通过management.server.port单独配置实现与管理端口的隔离,Prometheus集成需要引入micrometer-registry-prometheus依赖后暴露/prometheus端点。