SpringBoot2核心功能面试题库
生成时间:2026-05-21 23:32
本轮 SpringBoot2核心功能面试题库(带答案)
【面试题】1. SpringBoot启动类上的@SpringBootApplication注解由哪些注解组合而成?它们各自的作用是什么?
【标准答案】 @SpringBootApplication是一个组合注解,由三个核心注解组成:
第一,@SpringBootConfiguration,本质就是@Configuration,标记这是一个配置类,允许在类中定义@Bean方法。
第二,@ComponentScan,开启组件扫描,默认扫描当前包及其子包下所有带@Component、@Service、@Repository、@Controller注解的类,把它们注册成Bean。
第三,@EnableAutoConfiguration,这是自动配置的核心,通过@Import导入AutoConfigurationImportSelector,读取META-INF/spring.factories或org.springframework.boot.autoconfigure.AutoConfiguration.imports文件,加载所有自动配置类,再结合条件注解按需装配。
简单说:@Configuration负责定义Bean,@ComponentScan负责发现Bean,@EnableAutoConfiguration负责自动配置Bean。
【面试题】2. SpringBoot的条件注解@ConditionalOnProperty是如何工作的?实际项目中怎么用?
【标准答案】 @ConditionalOnProperty根据配置文件中的属性值决定是否生效。
核心属性有三个:
- prefix:属性前缀
- name或value:属性名
- havingValue:期望值
- matchIfMissing:属性不存在时是否生效,默认false
工作原理:容器启动时,会读取环境中的属性值,和havingValue比对,匹配则注册Bean,不匹配则跳过。
实际应用场景:开关控制。比如我要做一个短信服务,生产环境用阿里云,测试环境用Mock实现。配置文件里写sms.provider=aliyun,条件注解写@ConditionalOnProperty(prefix="sms", name="provider", havingValue="aliyun"),只有配置匹配时才生效。另一个Mock实现写havingValue="mock"。
关键是:条件注解在Bean定义阶段生效,不会创建不必要的Bean,节省资源。
【面试题】3. SpringBoot的配置文件加载顺序是怎样的?同名属性如何覆盖?
【标准答案】 配置加载顺序从高到低:
- 命令行参数,优先级最高,比如--server.port=8081
- Java系统属性,System.getProperties()
- 操作系统环境变量
- application-{profile}.yml/properties,比如application-dev.yml
- application.yml/properties,jar包外
- application.yml/properties,jar包内
- @PropertySource注解指定的配置文件
- 默认属性,SpringApplication.setDefaultProperties
覆盖规则很简单:同名属性,优先级高的覆盖低的。比如application.yml里server.port=8080,命令行写了--server.port=8081,最终生效8081。
实际开发中,我们常用多环境配置:application.yml写公共配置,application-dev.yml写开发环境特有配置,application-prod.yml写生产环境特有配置。启动时指定spring.profiles.active=dev或prod,对应的环境配置会覆盖公共配置中的同名属性。
【面试题】4. @ConfigurationProperties和@Value绑定配置有什么区别?怎么选择?
【标准答案】 区别主要体现在三个方面:
第一,绑定方式不同。@ConfigurationProperties是批量绑定,把整个配置块映射成一个Java对象,属性名自动匹配,支持松散绑定,比如my.app-name能映射到appName字段。@Value是单个属性注入,每个属性都要写@Value("${my.app-name}")。
第二,校验能力不同。@ConfigurationProperties配合@Validated可以做JSR303校验,比如@NotBlank、@Min(1),启动时校验,配置不合法直接报错。@Value没有校验能力。
第三,SpEL支持不同。@Value支持SpEL表达式,比如@Value("#{systemProperties['user.name']}")。@ConfigurationProperties不支持SpEL,只支持配置文件属性。
选择建议:配置项多、需要类型安全校验、需要复用,用@ConfigurationProperties。配置项少、简单场景、需要SpEL,用@Value。
实际项目推荐用@ConfigurationProperties,代码更清晰,维护更方便,IDE还有提示支持。
【面试题】5. BeanFactory和ApplicationContext有什么区别?SpringBoot启动用的是哪个?
【标准答案】 BeanFactory是Spring最基础的容器接口,提供Bean的获取和管理能力,采用延迟加载,调用getBean时才创建Bean。
ApplicationContext继承BeanFactory,扩展了更多功能:国际化、事件发布、资源加载、环境信息、AOP支持。默认采用立即加载,容器启动时就创建所有单例Bean。
区别总结:BeanFactory是基础容器,功能最少;ApplicationContext是高级容器,功能更全。
SpringBoot启动用的是ApplicationContext,具体实现类是AnnotationConfigServletWebServerApplicationContext。启动流程中,SpringApplication.run方法会创建ApplicationContext,调用refresh方法完成容器初始化,包括BeanFactory的创建、BeanDefinition的注册、Bean的实例化,最后返回ApplicationContext。
简单记忆:BeanFactory是引擎,ApplicationContext是整辆车。
【面试题】6. BeanPostProcessor和BeanFactoryPostProcessor的区别是什么?执行时机各是什么时候?
【标准答案】 BeanFactoryPostProcessor是BeanFactory的后置处理器,在BeanDefinition加载完成后、Bean实例化之前执行。可以修改BeanDefinition的属性,比如修改scope、lazy-init、property values。典型应用是PropertySourcesPlaceholderConfigurer,处理${...}占位符。
BeanPostProcessor是Bean的后置处理器,在Bean实例化后、初始化前后执行。有两个方法:postProcessBeforeInitialization在初始化方法之前调用,postProcessAfterInitialization在初始化方法之后调用。典型应用是AutowiredAnnotationBeanPostProcessor处理@Autowired、@Value注解,还有AOP代理创建。
执行时机:
- BeanFactoryPostProcessor:refresh的invokeBeanFactoryPostProcessors阶段
- Bean实例化
- BeanPostProcessor的Before方法
- 初始化方法(@PostConstruct、InitializingBean)
- BeanPostProcessor的After方法
一句话总结:BeanFactoryPostProcessor改定义,BeanPostProcessor改实例。
【面试题】7. Spring AOP中@Around、@Before、@AfterReturning、@AfterThrowing、@After的执行顺序是怎样的?
【标准答案】 执行顺序分两种情况:
正常执行时:
- @Around前半部分
- @Before
- 目标方法执行
- @AfterReturning
- @After
- @Around后半部分
异常执行时:
- @Around前半部分
- @Before
- 目标方法抛异常
- @AfterThrowing
- @After
关键点:@After是最终通知,无论正常还是异常都会执行,类似finally。@AfterReturning只在正常返回时执行,@AfterThrowing只在异常时执行。
如果同一个方法有多个切面,可以用@Order或实现Ordered接口控制顺序,数值越小优先级越高。@Order(1)的切面比@Order(2)先执行。
实际开发中,@Around最强大,可以控制目标方法是否执行、修改参数、修改返回值、捕获异常。其他通知适用于简单场景。
【面试题】8. SpringBoot的事件机制是怎么工作的?ContextRefreshedEvent在什么时机触发?
【标准答案】 Spring事件机制基于观察者模式,三个核心组件:
- ApplicationEvent:事件基类,自定义事件继承它
- ApplicationListener:事件监听器,实现onApplicationEvent方法
- ApplicationEventPublisher:事件发布器,通过ApplicationContext获取
SpringBoot内置事件按启动顺序:
- ApplicationStartingEvent:启动开始
- ApplicationEnvironmentPreparedEvent:环境准备完成
- ApplicationContextInitializedEvent:容器初始化
- ApplicationPreparedEvent:Bean定义加载完成
- ContextRefreshedEvent:容器刷新完成
- ApplicationStartedEvent:应用启动完成
- ApplicationReadyEvent:应用就绪
ContextRefreshedEvent在refresh方法的finishRefresh阶段触发,标志着所有Bean实例化完成、单例池填充完毕、容器完全可用。
监听方式两种:实现ApplicationListener接口,或用@EventListener注解。异步事件在方法上加@Async,需要先@EnableAsync。
【面试题】9. SpringBoot集成MyBatis时,@MapperScan和@Mapper注解有什么区别?
【标准答案】 @MapperScan是类注解,用在启动类或配置类上,批量扫描指定包下的所有接口,把它们注册成Mapper代理对象。比如@MapperScan("com.example.mapper"),扫描mapper包下所有接口。
@Mapper是接口注解,用在具体的Mapper接口上,标记这个接口需要被MyBatis处理。
区别:@MapperScan是批量注册,@Mapper是单独标记。两者可以共存,@MapperScan扫描的包不需要再写@Mapper,但如果Mapper接口在扫描包外,需要单独加@Mapper。
实际开发推荐用@MapperScan,配置一次就行,不用每个Mapper接口都写注解。
底层原理:@MapperScan通过@Import导入MapperScannerRegistrar,注册MapperScannerConfigurer这个BeanFactoryPostProcessor,扫描指定包,把接口注册成BeanDefinition,BeanClass是MapperFactoryBean,创建代理对象。
【面试题】10. SpringBoot的@Transactional注解在什么情况下会失效?怎么避免?
【标准答案】 失效场景主要有五种:
方法不是public,@Transactional只对public方法生效,因为CGLIB代理基于继承,private和protected方法无法被代理。
同一个类内部调用,事务方法A调用事务方法B,A没加事务,B的事务失效。因为调用不走代理,是this.方法调用。
异常被catch吞掉,默认只对RuntimeException回滚,如果catch住异常没抛出,事务不会回滚。可以指定rollbackFor = Exception.class。
数据库引擎不支持事务,比如MySQL的MyISAM。
传播行为设置错误,比如PROPAGATION_NOT_SUPPORTED以非事务方式运行。
解决方案:
- 方法必须是public
- 类内部调用要注入自己或用AopContext.currentProxy()
- 异常要抛出或指定rollbackFor
- 使用InnoDB引擎
- 默认传播行为REQUIRED,一般不用改
实际开发最容易踩坑的是类内部调用,要特别注意。