本轮 SpringBoot2核心功能面试题库(带答案)
生成时间:2026-05-21 22:47
【面试题】1. SpringBoot自动配置的"条件装配"是如何实现的?请结合@ConditionalOnClass举例说明。
【标准答案】 SpringBoot的条件装配核心是@Conditional系列注解,配合Condition接口实现。
原理层面:
@EnableAutoConfiguration导入AutoConfigurationImportSelector- 该Selector读取
META-INF/spring.factories或META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports - 对每个候选自动配置类,评估
@Conditional条件 - 条件通过则注册Bean,不通过则跳过
@ConditionalOnClass示例:
@Configuration
@ConditionalOnClass(DataSource.class) // classpath存在DataSource才生效
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource() {
return new HikariDataSource();
}
}底层实现:
@ConditionalOnClass注解被OnClassCondition类处理- 通过
ClassLoader尝试加载指定类,成功则条件成立 - 不需要实例化Bean,仅检查类是否存在
面试加分点:
- 条件注解在Bean实例化前执行,性能高效
- 可以组合多个条件:
@ConditionalOnClass+@ConditionalOnProperty等 - 自动配置的"按需加载"避免不必要的Bean创建
【面试题】2. SpringBoot配置文件的加载顺序是怎样的?优先级高的配置如何覆盖低的?
【标准答案】 SpringBoot配置加载遵循"外层覆盖内层、后加载覆盖先加载"原则:
优先级从高到低:
- 命令行参数
--server.port=8081 - JAR包外部的
application-{profile}.properties/yml - JAR包内部的
application-{profile}.properties/yml - JAR包外部的
application.properties/yml - JAR包内部的
application.properties/yml @PropertySource注解指定的配置- 默认属性
SpringApplication.setDefaultProperties
覆盖机制举例:
# 内部application.yml
server:
port: 8080
# 外部application.yml(与JAR同目录)
server:
port: 9090启动后端口为9090,外部配置覆盖内部。
关键源码: ConfigFileApplicationListener按优先级加载配置,后者覆盖前者同名属性。
面试加分点:
- "外部"指JAR所在目录,生产环境可通过外部配置实现运维解耦
spring.config.location可自定义配置文件路径spring.config.additional-location追加配置源而非覆盖
【面试题】3. 解释Spring Bean的完整生命周期,包括容器启动到Bean销毁的全过程。
【标准答案】 Bean生命周期分为实例化→属性赋值→初始化→使用→销毁五个阶段:
详细流程:
1. 实例化
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
- 构造函数创建Bean实例
2. 属性赋值
- InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
- @Autowired/@Value依赖注入
- InstantiationAwareBeanPostProcessor.postProcessPropertyValues()
3. 初始化(核心)
- Aware接口回调(BeanNameAware/ApplicationContextAware等)
- BeanPostProcessor.postProcessBeforeInitialization()
- @PostConstruct注解方法
- InitializingBean.afterPropertiesSet()
- 自定义init-method
- BeanPostProcessor.postProcessAfterInitialization() ← AOP代理在此创建
4. 使用
- Bean正常提供服务
5. 销毁
- @PreDestroy注解方法
- DisposableBean.destroy()
- 自定义destroy-method关键点:
BeanPostProcessor是扩展核心,AOP、事务注解在此生效InitializingBean比@PostConstruct执行早?错!实际顺序:@PostConstruct→InitializingBean→init-method
面试加分点:
- FactoryBean与普通Bean区别:FactoryBean通过
getObject()返回对象,可用于创建复杂Bean - BeanFactoryPostProcessor在Bean实例化前执行,可修改BeanDefinition
【面试题】4. SpringBoot中@Transactional事务传播行为REQUIRED和REQUIRES_NEW有什么区别?各适用什么场景?
【标准答案】 REQUIRED(默认):
- 存在事务则加入,不存在则新建
- 多个方法共享同一事务,任一方法回滚则整体回滚
REQUIRES_NEW:
- 总是新建独立事务,已存在事务被挂起
- 新事务独立提交/回滚,不影响外层事务
代码示例:
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void createOrder(Order order) {
orderDao.insert(order);
logService.saveLog(order); // 即使logService失败,order也不会回滚
}
}
@Service
public class LogService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(Order order) {
// 独立事务,失败不影响外层
logDao.insert(new Log(order));
}
}适用场景:
REQUIRED:常规业务操作,需要原子性REQUIRES_NEW:日志记录、发送通知等"必须执行但不能影响主业务"的场景
面试加分点:
- REQUIRES_NEW存在事务挂起开销,性能影响需考虑
- 同类方法调用@Transactional会失效(绕过代理),需通过AopContext或注入自身解决
- 事务传播仅对RuntimeException回滚,checked异常需配置
rollbackFor
【面试题】5. Spring AOP中JDK动态代理和CGLIB代理有什么区别?SpringBoot默认使用哪种?
【标准答案】 JDK动态代理:
- 基于接口,代理类实现与目标类相同的接口
- 目标类必须实现至少一个接口
- 生成的代理类调用
InvocationHandler.invoke()
CGLIB代理:
- 基于继承,生成目标类的子类
- 不要求接口,可代理普通类
- 通过方法重写实现增强,final方法无法代理
SpringBoot默认策略:
# SpringBoot 2.x 默认配置
spring.aop.proxy-target-class=true # 默认使用CGLIB源码逻辑: DefaultAopProxyFactory.createAopProxy():
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config); // 接口用JDK
}
return new ObjenesisCglibAopProxy(config); // 类用CGLIB面试加分点:
- Spring 5+ CGLIB不再依赖外部库,内置了CGLIB
@EnableAspectJAutoProxy(proxyTargetClass = true)强制使用CGLIB- 性能差异:JDK代理调用稍快,CGLIB创建稍慢(现代框架已优化差距很小)
- CGLIB无法代理
private和final方法
【面试题】6. SpringBoot如何实现自定义Starter?请描述核心步骤和注意事项。
【标准答案】 自定义Starter三要素:
1. 创建autoconfigure模块:
my-spring-boot-starter-autoconfigure/
├── src/main/java/
│ └── com/example/
│ ├── MyAutoConfiguration.java
│ ├── MyProperties.java
│ └── MyService.java
└── src/main/resources/
└── META-INF/spring/
└── org.springframework.boot.autoconfigure.AutoConfiguration.imports2. 核心代码:
@Configuration
@ConditionalOnClass(MyService.class)
@EnableConfigurationProperties(MyProperties.class)
public class MyAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public MyService myService(MyProperties properties) {
return new MyService(properties.getPrefix());
}
}
@ConfigurationProperties(prefix = "my.service")
public class MyProperties {
private String prefix = "default";
// getter/setter
}3. 注册自动配置: META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
com.example.MyAutoConfiguration注意事项:
- 命名规范:
xxx-spring-boot-starter(官方)vsspring-boot-starter-xxx(第三方) - 必须提供
spring-configuration-metadata.json支持IDE提示 - 使用
@ConditionalOnMissingBean允许用户覆盖默认Bean - 添加
@AutoConfigureAfter/@AutoConfigureBefore控制加载顺序
面试加分点:
- SpringBoot 2.7+推荐使用
.imports文件替代spring.factories - 可通过
spring.factories指定EnableAutoConfiguration实现兼容旧版本
【面试题】7. SpringBoot事件机制的原理是什么?如何在业务中使用ApplicationEvent?
【标准答案】 事件机制三要素:
ApplicationEvent- 事件对象ApplicationEventPublisher- 事件发布者ApplicationListener/@EventListener- 事件监听者
自定义事件示例:
// 1. 定义事件
public class OrderCreatedEvent extends ApplicationEvent {
private final Order order;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}
}
// 2. 发布事件
@Service
public class OrderService {
@Autowired
private ApplicationEventPublisher publisher;
public void createOrder(Order order) {
orderDao.save(order);
publisher.publishEvent(new OrderCreatedEvent(this, order));
}
}
// 3. 监听事件(两种方式)
@Component
public class OrderEventListener {
// 方式一:@EventListener注解
@EventListener
public void onOrderCreated(OrderCreatedEvent event) {
System.out.println("订单创建:" + event.getOrder());
}
// 方式二:实现ApplicationListener接口
// public class OrderEventListener implements ApplicationListener<OrderCreatedEvent>
}异步事件:
@EventListener
@Async // 配合@EnableAsync
public void onOrderCreated(OrderCreatedEvent event) {
// 异步处理,不阻塞主线程
}内置核心事件:
ContextRefreshedEvent- 容器刷新完成ContextStartedEvent- 容器启动ContextClosedEvent- 容器关闭ApplicationReadyEvent- 应用就绪
面试加分点:
- 事件默认同步执行,
@Async实现异步 @EventListener(condition = "...")支持SpEL条件过滤@TransactionalEventListener可绑定事务阶段(提交后/回滚后)
【面试题】8. SpringBoot Actuator如何实现自定义健康检查端点?
【标准答案】 内置端点:
/actuator/health- 应用健康状态/actuator/info- 应用信息/actuator/metrics- 指标数据
自定义HealthIndicator:
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// 检查逻辑
boolean healthy = checkExternalService();
if (healthy) {
return Health.up()
.withDetail("service", "External API")
.withDetail("responseTime", "120ms")
.build();
} else {
return Health.down()
.withDetail("service", "External API")
.withDetail("error", "Connection timeout")
.build();
}
}
private boolean checkExternalService() {
// 检查外部服务是否可用
return true;
}
}访问结果:
{
"status": "UP",
"components": {
"custom": {
"status": "UP",
"details": {
"service": "External API",
"responseTime": "120ms"
}
},
"db": { "status": "UP" }
}
}暴露配置:
management:
endpoints:
web:
exposure:
include: health,info,metrics # 或 "*" 暴露全部
endpoint:
health:
show-details: always # 显示详细信息面试加分点:
- 健康状态:UP/DOWN/OUT_OF_SERVICE/UNKNOWN
- 可组合多个健康检查:
HealthAggregator决定最终状态 - 生产环境需配合
Spring Security保护端点
【面试题】9. SpringBoot整合MyBatis时,@MapperScan和@Mapper有什么区别?
【标准答案】 @MapperScan(推荐):
- 配置在启动类或配置类上
- 批量扫描指定包下所有Mapper接口
- 无需每个Mapper都加注解
@Mapper:
- 配置在每个Mapper接口上
- 标记该接口为MyBatis Mapper
- 需要每个接口单独添加
代码对比:
// 方式一:@MapperScan(推荐)
@SpringBootApplication
@MapperScan("com.example.mapper") // 批量扫描
public class Application { }
// 方式二:@Mapper(每个接口单独标记)
@Mapper
public interface UserMapper {
User findById(Long id);
}
@Mapper
public interface OrderMapper {
Order findById(Long id);
}底层原理:
@MapperScan通过@Import(MapperScannerRegistrar.class)导入注册器MapperScannerRegistrar注册MapperScannerConfigurerMapperScannerConfigurer实现BeanDefinitionRegistryPostProcessor- 扫描包并将接口注册为
MapperFactoryBean
面试加分点:
@MapperScan可配置多个包:@MapperScan({"com.example.mapper", "com.example.dao"})@MapperScan支持自定义sqlSessionFactoryRef和sqlSessionTemplateRef- MyBatis-Plus无需
@MapperScan,使用@MappersScan(注意拼写) @Mapper和@MapperScan可同时使用,不冲突
【面试题】10. SpringBoot如何实现优雅停机?生产环境如何配置?
【标准答案】 优雅停机核心:
- 停止接收新请求
- 等待现有请求处理完成
- 释放资源、关闭连接
- 退出应用
配置方式:
server:
shutdown: graceful # 启用优雅停机
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # 等待超时内置机制:
- SpringBoot 2.3+ 内置
GracefulShutdown - 接收到
SIGTERM信号后进入优雅停机 SmartLifecycle实现类可自定义关闭逻辑
自定义关闭钩子:
@Component
public class GracefulShutdown implements DisposableBean, SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
running = true;
}
@Override
public void stop() {
// 清理资源
System.out.println("正在关闭,等待请求完成...");
running = false;
}
@Override
public boolean isRunning() {
return running;
}
@Override
public int getPhase() {
return Integer.MAX_VALUE; // 最后关闭
}
@Override
public void destroy() throws Exception {
System.out.println("资源已释放");
}
}Kubernetes配置:
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"] # 等待Service剔除面试加分点:
getPhase()返回值越大越晚关闭,越小越早关闭- Actuator的
/actuator/shutdown端点可触发优雅停机(需手动开启) - 线程池需自行处理:
executor.shutdown()+awaitTermination() - 数据库连接池Druid/HikariCP已内置优雅关闭