面经资料
spring 三级缓存是什么?
三级缓存主要是为了解决单例模式下的循环依赖的问题。
循环依赖指的是两个类中的属性相互依赖对方:例如 A 类中有 B 属性,B 类中有 A属性,从而形成了一个依赖闭环,如下图。
循环依赖问题在Spring中主要有三种情况:
- 第一种:通过构造方法进行依赖注入时产生的循环依赖问题。
- 第二种:通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
- 第三种:通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
第一种示例,构造方法循环依赖(无法解决)
@Service
public class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
@Service
public class ServiceB {
private final ServiceA serviceA;
@Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
}
}
第二种示例,多例模式的 ServiceC 和 ServiceD
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class ServiceC {
private ServiceD serviceD;
@Autowired
public void setServiceD(ServiceD serviceD) {
this.serviceD = serviceD;
}
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class ServiceD {
private ServiceC serviceC;
@Autowired
public void setServiceC(ServiceC serviceC) {
this.serviceC = serviceC;
}
}
第三种:Setter+单例模式循环依赖(可以解决)
@Service
public class ServiceE {
private ServiceF serviceF;
@Autowired
public void setServiceF(ServiceF serviceF) {
this.serviceF = serviceF;
}
}
@Service
public class ServiceF {
private ServiceE serviceE;
@Autowired
public void setServiceE(ServiceE serviceE) {
this.serviceE = serviceE;
}
}
Spring的三重缓存机制
singletonObjects 完全初始化好的单例Bean 直接获取可用Bean
earlySingletonObjects 提前暴露的未完成初始化的Bean 解决循环依赖
singletonFactories 生成早期引用的ObjectFactory 延迟处理Bean的后处理器
面试话术 "Spring解决循环依赖的核心在于三级缓存机制,但这仅适用于单例模式下的Setter/字段注入。构造器注入因必须在创建阶段完成依赖注入,而原型模式因无法缓存中间状态,均会导致无法解决的循环问题。理解这一点对设计松耦合的Spring应用至关重要。"
三级缓存都是ConcurrentHashMap
吗?
不是,只有一级缓存是ConcurrentHashMap
,三级缓存也就是DefaultSingletonBeanRegistry中的三个Map:
/* Cache of singleton objects: bean name to bean instance. 一级缓存*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of early singleton objects: bean name to bean instance. 二级缓存*/
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Cache of singleton factories: bean name to ObjectFactory. 三级缓存*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
但是在 spring 2.7.10新版本开始,earlySingletonObjects(二级缓存)改成使用 ConcurrentHashMap。
继承和接口的区别?什么时候用继承,什么时候用接口呢?
继承 | 接口 |
---|---|
子类拥有父类的所有属性和方法 | 子类必须实现接口中的所有方法 |
是"is-a"的关系 | 是"can-do"的关系 |
提供代码复用 | 要实现所有接口方法 |
如何选择? 优先用接口:
需要定义行为规范而非具体实现(如Comparable定义比较逻辑)。
类需要多种不相关的能力(如既能保存到数据库,又能导出为JSON)。
优先用继承:
存在清晰的层次关系且需要代码复用(如Exception类继承体系)。
需要覆盖父类方法实现多态(如Animal的makeSound()方法被不同子类重写)。