每日面试题—2026.01.31
1. 什么是Spring自动装配?
Spring的自动装配是IOC容器依据特定规则,自动给Bean注入依赖,而不需要手动new或者显式配置依赖关系。
它的触发注解是@Autowired,底层是依赖于Bean的自动注入(DI)实现的。
他的实现过程是这样:
- 第一步:容器启动时会自动扫描带有
@Component注解或者@Service等@Component的子类注解,将其标注的类解析为BeanDefinition,同时实例化为Bean存到IOC容器中 - 第二步:会通过AutowiredAnnotationPostProcessor后置处理器,扫描Bean中的的
@Autowired,@Resource等注解,将其标记为依赖项 - 第三步:会按依赖项的依赖类型去IOC容器中查找,如果只有一个类型就直接进行依赖注入;如果有多个类型会通过依赖项的名称进行依赖注入或者会通过
@Qualifier指定优先级进行依赖匹配 - (这里官方推荐的注入方式是构造注入>set注入>字段注入)
- 第四步:将找到的依赖进行注入,完成自动装配
2. 什么是SpringBoot的自动装配?
SpringBoot的自动装配核心是基于Spring自动装配能力的扩展,不需要写大量的配置类,体现了SpringBoot约定大于配置的要点。
SpringBoot自动装配过程是这样:
- 第一步:SpringBoot项目启动时会触发一个EnableAutoConfiguration注解,这个注解会触发AutoConfigurationImportSelector类
- 第二步:AutoConfigurationImportSelector类会进一步调用SpringFactoriesLoader,去扫描META-INF/Spring.factories的配置文件(SpringBoot2.7以前),或者是META-INF/spring/org/springframework.boot.autoconfigure.AutoConfiguration.imports配置文件(SpringBoot2.7以后)
- 第三步:会按需加载配置文件对应的配置类,如DateSourceAutoConfiguration,SpringMVCAutoConfiguration等(这里按需是因为这些配置类有好多Canditional(条件)注解)
- 第四步:将满足条件的Bean进行注入到IOC容器中,再通过Spring自动装配能力完成依赖注入,这样就完成了SpringBoot的自动装配。
3. IOC和AOP的核心概念?
IOC:也被叫做控制反转,它的核心是反转对象的创建和依赖管理权,由开发者手动new对象,管理依赖,转交给Spring IOC容器进行统一的创建,存储,装配和管理。核心实现是依赖注入(DI),目的是解耦组件间依赖
IOC是Spring的核心骨架,管理所有Bean的生命周期和依赖。为AOP提供基础(AOP的切面,通知类,他们都需要IOC管理)。
AOP:也被叫做面向切面编程,核心是无侵入的进行增强代码功能,把日志,事务,鉴权校验等重复公共逻辑(切面)抽离,在目标方法执行的指定时机(切点)自动切入,不修改业务代码,实现业务与公共功能解耦
AOP是IOC的功能增强,基于IOC容器实现切面的动态织入,两者共同支撑了Spring的核心生态。
4. 出现循环依赖的问题如何解决?
先解释一下什么是循环依赖:两个及以上对象 / Bean 互相持有对方的引用,形成闭环引用,比如A依赖B,B又依赖A;或A→B→C→A的环形依赖。
对于手动的new对象,会直接导致实例化死循环 / 堆溢出(比如 A 的构造器 new B,B 的构造器 new A)。
对于Spring框架来说:框架对单例 Bean 的 setter 注入 / 字段注入做了处理,能解决大部分循环依赖,但构造器注入的单例 Bean、多例 Bean的循环依赖框架无法处理,会抛出BeanCurrentlyInCreationException。
Spring默认已解决的循环依赖场景:
Spring 容器仅能解决单例作用域下,通过setter 注入 / 字段注入(@Autowired)/ 方法注入的 Bean 循环依赖,它的底层通过三级缓存实现:
- 一级缓存(singletonObjects):存放完全初始化完成的单例 Bean;
- 二级缓存(earlySingletonObjects):存放提前暴露的、已实例化但未完成属性注入 / 初始化的 Bean;
- 三级缓存(singletonFactories):存放 Bean 的工厂对象,用于动态创建代理对象并提前暴露。
核心逻辑:将 Bean 的创建过程拆分为「实例化」和「初始化(属性注入 + 初始化方法)」两个阶段,在实例化后立即将半成品 Bean 提前暴露到三级缓存中,当后续依赖注入发现目标 Bean 正在创建时,直接从缓存中获取半成品 Bean 完成注入,从而打破 “互相等待对方创建完成” 的死循环。
Spring无法解决的循环依赖场景 & 解决方案
场景 1:构造器注入导致的单例 Bean 循环依赖(最常见)
问题:A 的构造器入参是 B,B 的构造器入参是 A,Spring 实例化时需要先创建依赖对象,形成死循环。
1. 改为 setter 注入 / 字段注入(最推荐,符合 Spring 原生支持)
移除构造器中的依赖,改用@Autowired字段注入或 setter 上标注@Autowired:
1 | // 原错误:构造器注入循环依赖 |
2. 使用@Lazy懒加载(适合不想改注入方式的场景)
在构造器入参上标注@Lazy,让 Spring 创建代理对象而非真实对象,延迟真实对象的初始化,打破循环:
1 |
|
3. 使用@DependsOn指定依赖加载顺序(兜底方案,慎用)
强制指定 Bean 的创建顺序,让其中一个 Bean 先完成初始化,适合复杂场景:
1 |
|
场景 2:多例(prototype)Bean 的循环依赖
问题:Spring 对prototype(每次获取都新建)Bean 不做缓存,因此无法通过三级缓存提前暴露半成品对象,无论哪种注入方式,循环依赖都会报错。
1. 改为单例(singleton)Bean(最推荐,大部分业务 Bean 无需多例);
2. 手动获取 Bean(通过ApplicationContext按需获取,放弃 Spring 自动注入):
让 Bean 实现ApplicationContextAware,从容器中手动获取依赖的 Bean,避免自动注入的循环:
1 |
|
场景 3:单例 Bean 的代理对象循环依赖(如 AOP 增强的 Bean)
问题:Bean 被 AOP(@Transactional/@Aspect)增强,Spring 会创建代理对象,若代理对象参与循环依赖,三级缓存的工厂会动态创建代理对象,若配置不当会报错。
1. 使用@Lazy配合代理(通用方案);
2. 开启 Spring 的allowRawInjectionDespiteWrapping配置(SpringBoot),允许原始对象注入(兜底)
1 | # application.yml |
场景 4:自定义 BeanPostProcessor 导致的循环依赖
问题:自定义的BeanPostProcessor在 Bean 初始化前做增强,若处理器中依赖了循环依赖的 Bean,会打断 Spring 的三级缓存流程。
1. 让自定义BeanPostProcessor实现PriorityOrdered,提高执行优先级;
2. 避免在BeanPostProcessor中注入循环依赖的 Bean,改用ApplicationContext手动获取。
场景 5:纯 Java 代码(非 Spring)的循环依赖解决(面试延伸题)
方案 1:拆分构造器,通过 setter 后续赋值(最常用)
先无参构造实例化对象,再通过 setter 方法设置依赖,避免构造器中互相 new:
1 | // 原错误:构造器循环new,导致栈溢出 |
方案 2:使用懒加载(延迟创建依赖对象)
通过懒加载初始化(比如第一次使用时才创建依赖),避免初始化时的循环:
1 | public class A { |
方案 3:引入中间层 / 拆分业务(从根源解决)
循环依赖的本质往往是类的职责过于臃肿,违反单一职责原则,拆分类的功能,抽离公共逻辑到中间层,从根源消除循环依赖(工程化最佳实践)。
示例:A 依赖 B 的支付功能,B 依赖 A 的订单功能→抽离PayService和OrderService作为中间层,A 和 B 分别依赖中间层,而非互相依赖。
根源规避:遵循单一职责原则拆分类、引入中间层解耦、基于接口编程,从设计上消除循环依赖。
5. 为什么JDK1.8的HashMap要引入红黑树?
JDK1.8 的 HashMap 引入红黑树,核心是优化哈希冲突后链表过长的性能问题,具体原因和设计考量如下:
- 解决性能退化:JDK1.7 及之前是数组 + 链表,哈希冲突严重时链表会极长,导致get/put操作从 O (1) 退化到 O (n),红黑树将其稳定在 O (logn),极端场景下保证 HashMap 的性能;
- 红黑树是最优选择:红黑树是弱平衡二叉搜索树,相比严格平衡的 AVL 树,插入 / 删除的旋转开销更小,适配 HashMap 读写频繁的场景;相比普通二叉查找树,不会因有序插入退化为链表,保证结构有效性;
- 按需树化,避免过度优化:设置了链表转红黑树的双阈值(节点≥8、数组容量≥64),且红黑树节点≤6 时退化为链表,兼顾了不同节点数量下的效率,避免无意义的树维护开销。
6. 什么是MCP?
- MCP 即 Mesh Configuration Protocol,服务网格配置协议,是云原生服务网格领域的标准化控制面通信协议,基于 gRPC+Protobuf 实现。
- 它主要用于服务网格控制面组件之间、多集群控制面之间、控制面与配置源之间,完成路由策略、安全规则、服务信息的标准化、增量、可靠同步,解决早期控制面耦合、多集群配置不一致、异构配置源无法互通的问题。
- MCP 与数据面使用的 xDS 协议互补:xDS 负责控制面到 Envoy 数据面的转发规则下发,MCP 负责控制面内部及跨集群的配置同步,是现代服务网格实现解耦、扩展、多集群统一治理的关键协议。





