本轮 SpringBoot2核心功能面试题库(带答案)
生成时间:2026-05-22 22:11
【面试题】1. SpringBoot自动配置的"开关"机制是什么?@ConditionalOnProperty是如何工作的?
【标准答案】@ConditionalOnProperty是SpringBoot条件装配的核心注解之一,它通过检查Spring Environment中的属性值来决定是否注册Bean。关键属性有三个:prefix/value指定配置项前缀或名称,havingValue指定期望值,matchIfMissing指定当属性不存在时是否匹配(默认false)。底层走的是Spring的Condition接口,SpringBoot封装了SpringBootCondition抽象类,@ConditionalOnProperty对应的OnPropertyCondition会在匹配时读取Environment中的属性,和havingValue做比对。典型场景:server.ssl.enabled默认false,所以嵌入式容器不会自动配置HTTPS。面试时注意强调:它不是简单的等于判断,havingValue和属性值做的是字符串比较,matchIfMissing让你能做到"默认启用"的优雅降级——属性不写就生效,显式写false才关闭。
【面试题】2. @ConfigurationProperties和@Value绑定的区别是什么?松散绑定的规则是怎样的?
【标准答案】核心区别有三点:第一,@ConfigurationProperties是批量绑定,把整个prefix下的属性映射到一个POJO;@Value是逐个注入,适合少量值。第二,@ConfigurationProperties支持松散绑定,@Value不支持。第三,@ConfigurationProperties可以配合@Validated做JSR-303校验,@Value不行。松散绑定规则:配置文件中的属性名可以用kebab-case(my-prop-name)、underscore(my_prop_name)、大写(MY_PROP_NAME)等形式,最终都会映射到Java的myPropName字段。但注意一个坑:@ConfigurationProperties的prefix本身必须用kebab-case规范写法,不能用驼峰。另外,@ConfigurationProperties需要在启动类加@EnableConfigurationProperties或在类上加@Component才能生效,它本身不会自动注册Bean。
【面试题】3. BeanFactory和ApplicationContext有什么区别?SpringBoot启动时用的是哪个?
【标准答案】BeanFactory是Spring的最底层容器接口,只提供最基本的IoC功能——getBean、类型查询等,懒加载策略,Bean默认在首次获取时才创建。ApplicationContext是BeanFactory的超集,继承了好几个接口:MessageSource(国际化)、ResourcePatternResolver(资源加载)、ApplicationEventPublisher(事件发布)、EnvironmentCapable(环境配置)。ApplicationContext默认预加载所有单例Bean。SpringBoot启动时创建的是AnnotationConfigServletWebServerApplicationContext(Web场景)或AnnotationConfigApplicationContext(非Web场景),都是ApplicationContext的实现。面试要点:不要只说"ApplicationContext功能更多",要说清楚继承体系——ApplicationContext extends BeanFactory,所以它拥有BeanFactory的所有能力加上企业级特性。SpringBoot不会直接用纯BeanFactory,因为自动配置、事件机制、资源加载都需要ApplicationContext体系支撑。
【面试题】4. BeanPostProcessor和BeanFactoryPostProcessor的执行时机和作用分别是什么?
【标准答案】这是两个不同阶段的扩展点。BeanFactoryPostProcessor在BeanDefinition注册完成后、Bean实例化之前执行,操作的是BeanDefinition——可以修改Bean的属性值、作用域等元数据,典型代表是PropertySourcesPlaceholderConfigurer,它负责把${...}占位符替换成实际值。BeanPostProcessor在Bean实例化之后执行,分前后两个回调:postProcessBeforeInitialization在初始化回调(@PostConstruct、InitializingBean.afterPropertiesSet)之前,postProcessAfterInitialization在初始化回调之后。BeanPostProcessor操作的是Bean实例本身,典型代表是AutowiredAnnotationBeanPostProcessor处理@Autowired注入、CommonAnnotationBeanPostProcessor处理@PostConstruct/@PreDestroy。执行顺序:BeanFactoryPostProcessor → Bean实例化 → BeanPostProcessor.before → @PostConstruct → InitializingBean.afterPropertiesSet → BeanPostProcessor.after。面试加分点:AOP代理就是在BeanPostProcessor.after阶段由AbstractAutoProxyCreator创建的。
【面试题】5. @Import有哪三种使用方式?它们各自的底层原理是什么?
【标准答案】@Import三种方式:第一种,直接导入配置类——@Import(DataSourceConfig.class),等价于在当前配置类里直接写这个类的@Bean方法,底层Spring会把它当作@Configuration类处理,注册其中所有BeanDefinition。第二种,导入ImportSelector实现类——@Import(EnableAutoConfigurationImportSelector.class),ImportSelector的selectImports方法返回String[]全限定类名数组,Spring会把这些类注册为BeanDefinition,SpringBoot的自动配置就是靠DeferredImportSelector实现的(它延迟到所有@Configuration处理完才执行)。第三种,导入ImportBeanDefinitionRegistrar实现类——@Import(MyRegistrar.class),直接拿到BeanDefinitionRegistry手动注册BeanDefinition,MyBatis的@MapperScan底层就用这种方式注册MapperFactoryBean。面试要点:三种方式的控制粒度递增——ImportSelector适合批量导入(返回类名即可),ImportBeanDefinitionRegistrar适合需要动态、条件性注册的场景(直接操作Registry)。
【面试题】6. SpringBoot的嵌入式容器是如何自动配置的?如何切换为Undertow?
【标准答案】SpringBoot通过ServletWebServerApplicationContext和对应的自动配置类实现嵌入式容器的自动装配。以Tomcat为例:ServletWebServerFactoryAutoConfiguration导入ServletWebServerFactoryConfiguration.EmbeddedTomcat配置类,@ConditionalOnClass({Servlet.class, Tomcat.class})条件下注册TomcatServletWebServerFactory这个Bean。SpringApplication.run启动时,调refreshContext → onRefresh → createWebServer,从容器中获取ServletWebServerFactory Bean,调用getWebServer方法启动Tomcat。切换Undertow只需三步:第一步排除Tomcat依赖(spring-boot-starter-web中exclusion spring-boot-starter-tomcat),第二步引入spring-boot-starter-undertow,第三步无需任何代码改动。自动配置类会检测到Undertow的类在classpath中且Tomcat不在,自动切换。Undertow的优势:内存占用更小、高并发非阻塞IO性能更好,适合云原生轻量场景。
【面试题】7. SpringBoot事件机制的发布顺序是怎样的?ContextRefreshedEvent在什么时机触发?
【标准答案】SpringBoot应用启动过程中,内置核心事件的严格发布顺序:ApplicationStartingEvent → ApplicationEnvironmentPreparedEvent → ApplicationContextInitializedEvent → ApplicationPreparedEvent → ContextRefreshedEvent → ContextStartedEvent → ApplicationStartedEvent → ApplicationReadyEvent。ContextRefreshedEvent在ApplicationContext刷新完成时触发,即所有BeanDefinition已注册、所有单例Bean已实例化、所有BeanPostProcessor已执行、所有初始化回调已完成。ContextStartedEvent在显式调用ConfigurableApplicationContext.start()时触发(默认启动不会触发,需要手动调start)。ApplicationStartedEvent在上下文刷新后、ApplicationRunner/CommandLineRunner执行前触发。ApplicationReadyEvent在Runner执行完毕后触发,标志着应用完全就绪。面试踩坑点:ContextRefreshedEvent可能触发多次——如果你有父子容器(如SpringMVC的DispatcherServlet会创建子容器),子容器刷新时也会触发此事件。判断方式:event.getApplicationContext().getParent() == null表示根容器。
【面试题】8. @Transactional的传播行为有哪些?REQUIRED和REQUIRES_NEW在源码层面有什么区别?
【标准答案】7种传播行为,面试常考三种:REQUIRED(默认)——当前有事务就加入,没有就新建;REQUIRES_NEW——无论当前有没有事务,都新建一个独立事务,挂起外层事务;NESTED——当前有事务就在嵌套事务中执行(savepoint回滚不影响外层),没有就新建。源码层面差异在AbstractPlatformTransactionManager.handleExistingTransaction方法:REQUIRED走的是join逻辑,直接返回已有事务的status,不创建新的;REQUIRES_NEW调用suspend挂起当前事务(把ConnectionHolder、隔离级别等保存到SuspendedResourcesHolder),然后doBegin开启新连接新事务;NESTED在JDBC下调用Connection.setSavepoint创建保存点,回滚时只回滚到savepoint。关键点:REQUIRES_NEW的内层事务回滚不影响外层,但内层抛checked异常时外层仍能继续;但如果内层抛出的异常被外层catch了但内层标记了rollback-only,外层提交时会抛UnexpectedRollbackException——这是面试最爱问的坑。
【面试题】9. SpringBoot Actuator端点的安全暴露策略怎么配?如何自定义HealthIndicator?
【标准答案】Actuator端点默认只有/health和/info通过HTTP暴露,其他端点虽然已启用但未暴露。配置方式:management.endpoints.web.exposure.include=暴露全部,或指定具体端点如health,info,metrics,env;management.endpoints.web.exposure.exclude=env在include=的基础上排除敏感端点。安全策略建议:生产环境绝不要include=*,按需暴露,配合management.endpoints.web.base-path改路径、management.server.port用独立端口(如8081)与管理端口分离,再配合Spring Security做端点鉴权。自定义HealthIndicator两步走:第一步实现HealthIndicator接口,在health()方法中返回Health.up().withDetail("db", "可达").build()或Health.down().withDetail("redis", "连接超时").build();第二步加@Component注解自动注册,health端点名默认取类名去掉HealthIndicator后缀转小写。也可以用AbstractHealthIndicator简化代码。默认health端点只显示status,需要配置management.endpoint.health.show-details=always或when-authorized才能看到各Indicator的详细信息。
【面试题】10. SpringBoot分层JAR是什么?Docker镜像如何利用分层优化构建?
【标准答案】SpringBoot从2.3.0开始支持分层JAR。传统fat jar内部是扁平结构,改一行代码整个JAR都要重新构建和推送。分层JAR把依赖和应用类按变化频率分成多层:dependencies(第三方依赖,变化最少)、spring-boot-loader(加载器)、snapshot-dependencies(SNAPSHOT依赖)、application(项目自身类,变化最频)。每个层是一个独立的目录,Docker镜像中对应独立的layer。使用方式:第一步,spring-boot-maven-plugin配置<layers><enabled>true</enabled></layers>启用分层;第二步,用java -Djarmode=layertools -jar app.jar list查看分层顺序,java -Djarmode=layertools -jar app.jar extract解压出各层目录;第三步,Dockerfile中每层单独COPY,把dependencies层放最上面(Docker缓存最稳定),application层放最下面。这样改代码只重建最底层,前面的层命中Docker缓存,构建速度从分钟级降到秒级。面试加分:配合spring-boot:build-image直接生成分层OCI镜像,不用手写Dockerfile,底层用Paketo Buildpacks。