第2题:如何实现一个 IOC 容器?
📚 回答:
- 核心考点 : 手写 IOC 容器是面试中检验候选人是否真正理解 Spring 原理的"试金石"。面试官不会满足于"扫描包、反射创建对象、字段注入"这种玩具级实现,而是期望你展现 BeanDefinition 元数据抽象 、单例池与作用域管理 、构造器注入的递归解析 、三级缓存解决循环依赖 、以及 BeanPostProcessor 扩展点设计 等工程级设计能力。面试官真正想判断的是:你是否理解 Spring 从"配置"到"对象"的完整映射链路,以及如何在设计中预留扩展性。
1. IOC 容器的核心架构设计
一个工程级的 IOC 容器至少包含 5 个核心模块:citation:3citation:6
| 模块 | 职责 | 对应 Spring 组件 |
|---|---|---|
| 配置解析模块 | 解析 XML/注解/JavaConfig,提取 Bean 元数据 | BeanDefinitionReader |
| Bean 定义注册模块 | 存储 Bean 的类名、作用域、依赖关系等元数据 | BeanDefinitionRegistry |
| Bean 实例化模块 | 根据 BeanDefinition 反射创建对象 | AbstractAutowireCapableBeanFactory |
| 依赖注入模块 | 解析并注入构造器/字段/Setter 依赖 | AutowiredAnnotationBeanPostProcessor |
| 生命周期扩展模块 | 提供初始化前后、销毁时的扩展点 | BeanPostProcessor |
2. 第一步:定义核心注解
首先定义容器所需的自定义注解,模拟 Spring 的 @Component、@Autowired、@Qualifier、@Scope:
java
// 标记类为 Bean,由容器管理
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default ""; // Bean 名称,默认类名首字母小写
}
// 依赖注入标记
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR})
public @interface Autowired {
boolean required() default true;
}
// 指定注入的 Bean 名称(处理同类型多实例)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
public @interface Qualifier {
String value();
}
// 作用域:singleton(默认)或 prototype
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value() default "singleton";
}
3. 第二步:BeanDefinition------Bean 的"元数据描述"
BeanDefinition 是 IOC 容器的核心数据结构,存储 Bean 的所有元信息,而非 Bean 实例本身:citation:3citation:6
java
public class BeanDefinition {
private Class<?> beanClass; // Bean 的 Class 对象
private String beanName; // Bean 唯一标识
private String scope = "singleton"; // 作用域:singleton/prototype
private boolean lazyInit = false; // 是否延迟初始化
private Constructor<?> constructor; // 构造器(用于构造器注入)
private List<PropertyValue> propertyValues = new ArrayList<>(); // 属性依赖
private List<ConstructorArg> constructorArgs = new ArrayList<>(); // 构造器参数
// Getter/Setter...
}
// 属性值封装
public class PropertyValue {
private String name; // 属性名
private Object value; // 属性值(可能是引用其他 Bean 的 RuntimeBeanReference)
// ...
}
// 构造器参数封装
public class ConstructorArg {
private Class<?> type; // 参数类型
private Object value; // 参数值
private String ref; // 引用的 Bean 名称
// ...
}
关键设计 :BeanDefinition 解耦了"配置信息"和"实例对象",容器启动时先加载所有 BeanDefinition,再根据依赖关系按需或预加载实例。citation:6
4. 第三步:配置解析与 BeanDefinition 注册
-
4.1 包扫描解析(注解驱动) 扫描指定包路径下的所有类,识别
@Component注解,生成BeanDefinition:javapublic class ClassPathBeanDefinitionScanner { private BeanDefinitionRegistry registry; public void scan(String... basePackages) { for (String basePackage : basePackages) { Set<Class<?>> classes = scanPackage(basePackage); for (Class<?> clazz : classes) { if (clazz.isAnnotationPresent(Component.class)) { BeanDefinition bd = parseBeanDefinition(clazz); registry.registerBeanDefinition(bd.getBeanName(), bd); } } } } private BeanDefinition parseBeanDefinition(Class<?> clazz) { BeanDefinition bd = new BeanDefinition(); bd.setBeanClass(clazz); // 解析 @Component 的 value 作为 Bean 名称 Component component = clazz.getAnnotation(Component.class); String beanName = component.value(); if (beanName.isEmpty()) { beanName = Introspector.decapitalize(clazz.getSimpleName()); // 首字母小写 } bd.setBeanName(beanName); // 解析 @Scope if (clazz.isAnnotationPresent(Scope.class)) { bd.setScope(clazz.getAnnotation(Scope.class).value()); } // 解析构造器(优先找 @Autowired 构造器,否则找无参构造器) Constructor<?> autowiredCtor = findAutowiredConstructor(clazz); bd.setConstructor(autowiredCtor != null ? autowiredCtor : clazz.getDeclaredConstructor()); // 解析 @Autowired 字段作为 propertyValues for (Field field : clazz.getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { PropertyValue pv = new PropertyValue(); pv.setName(field.getName()); // 如果有 @Qualifier,记录引用名 if (field.isAnnotationPresent(Qualifier.class)) { pv.setValue(new RuntimeBeanReference( field.getAnnotation(Qualifier.class).value())); } else { pv.setValue(new RuntimeBeanReference(field.getType())); } bd.getPropertyValues().add(pv); } } return bd; } } -
4.2 BeanDefinitionRegistry------注册表实现
BeanDefinitionRegistry本质是一个Map<String, BeanDefinition>,负责 Bean 定义的增删查:citation:3javapublic class DefaultBeanDefinitionRegistry implements BeanDefinitionRegistry { // 核心存储:Bean 名称 → BeanDefinition private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(); // 按注册顺序存储 Bean 名称 private final List<String> beanDefinitionNames = new ArrayList<>(); @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) { // 去重检查 if (beanDefinitionMap.containsKey(beanName)) { throw new BeanDefinitionStoreException("Duplicate bean name: " + beanName); } beanDefinitionMap.put(beanName, beanDefinition); beanDefinitionNames.add(beanName); } @Override public BeanDefinition getBeanDefinition(String beanName) { BeanDefinition bd = beanDefinitionMap.get(beanName); if (bd == null) { throw new NoSuchBeanDefinitionException(beanName); } return bd; } @Override public boolean containsBeanDefinition(String beanName) { return beanDefinitionMap.containsKey(beanName); } @Override public String[] getBeanDefinitionNames() { return beanDefinitionNames.toArray(new String[0]); } }
5. 第四步:Bean 实例化与依赖注入
-
5.1 单例池与三级缓存设计 工程级 IOC 容器必须支持单例管理和循环依赖解决:citation:1
javapublic abstract class AbstractBeanFactory implements BeanFactory { // 一级缓存:成品单例池(完全初始化的 Bean) protected final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 二级缓存:早期引用(已实例化但未注入属性的 Bean) protected final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(); // 三级缓存:Bean 工厂(用于生成早期引用,支持 AOP 代理) protected final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(); // 正在创建中的 Bean(循环依赖检测) protected final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>()); @Override public Object getBean(String beanName) { // 1. 先从一级缓存获取 Object singleton = singletonObjects.get(beanName); if (singleton != null) return singleton; // 2. 再从二级缓存获取 singleton = earlySingletonObjects.get(beanName); if (singleton != null) return singleton; // 3. 从三级缓存获取工厂并创建 ObjectFactory<?> factory = singletonFactories.get(beanName); if (factory != null) { singleton = factory.getObject(); earlySingletonObjects.put(beanName, singleton); singletonFactories.remove(beanName); return singleton; } // 4. 创建 Bean return createBean(beanName, getBeanDefinition(beanName)); } } -
5.2 构造器注入的递归解析 构造器注入需要递归解析所有参数依赖,是 IOC 容器最复杂的部分:
javapublic class DefaultBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory, BeanDefinitionRegistry { @Override protected Object createBean(String beanName, BeanDefinition bd) { // 标记为"正在创建"(循环依赖检测) singletonsCurrentlyInCreation.add(beanName); try { // 1. 实例化(构造器注入在此阶段完成) Object bean = instantiateBean(bd); // 2. 放入三级缓存(暴露早期引用,解决循环依赖) singletonFactories.put(beanName, () -> bean); // 3. 属性填充(字段注入) populateBean(beanName, bean, bd); // 4. 初始化(执行初始化方法、BPP 前后处理) bean = initializeBean(beanName, bean, bd); // 5. 移入一级缓存 singletonObjects.put(beanName, bean); earlySingletonObjects.remove(beanName); singletonFactories.remove(beanName); return bean; } finally { singletonsCurrentlyInCreation.remove(beanName); } } private Object instantiateBean(BeanDefinition bd) { Constructor<?> ctor = bd.getConstructor(); Class<?>[] paramTypes = ctor.getParameterTypes(); if (paramTypes.length == 0) { // 无参构造器:直接反射创建 return ctor.newInstance(); } // 有参构造器:递归解析每个参数的依赖 Object[] args = new Object[paramTypes.length]; for (int i = 0; i < paramTypes.length; i++) { // 优先按类型查找,再按名称查找 String depBeanName = resolveDependency(paramTypes[i], bd.getConstructorArgs().get(i)); args[i] = getBean(depBeanName); // 递归调用 getBean,可能触发循环依赖 } return ctor.newInstance(args); } private void populateBean(String beanName, Object bean, BeanDefinition bd) { for (PropertyValue pv : bd.getPropertyValues()) { Field field = bean.getClass().getDeclaredField(pv.getName()); field.setAccessible(true); Object value = pv.getValue(); if (value instanceof RuntimeBeanReference) { // 引用类型:从容器获取依赖 Bean RuntimeBeanReference ref = (RuntimeBeanReference) value; String depBeanName = ref.getBeanName(); if (depBeanName == null) { // 按类型查找 depBeanName = resolveBeanNameByType(ref.getBeanType()); } value = getBean(depBeanName); // 递归获取依赖 } field.set(bean, value); } } } -
5.3 循环依赖检测 在构造器注入中,如果检测到循环依赖,需要抛出异常或采取特殊处理:
javaprivate Object getBean(String beanName) { // 循环依赖检测:如果当前 Bean 正在创建中,说明存在循环依赖 if (singletonsCurrentlyInCreation.contains(beanName)) { // 尝试从三级缓存获取早期引用 ObjectFactory<?> factory = singletonFactories.get(beanName); if (factory != null) { return factory.getObject(); // 返回早期引用(半成品) } // 构造器循环依赖无法解决(早期引用还未放入缓存) throw new BeanCurrentlyInCreationException( "Circular dependency detected for bean '" + beanName + "'"); } // ... 正常创建流程 }
6. 第五步:BeanPostProcessor 扩展点设计
为了让容器具备 AOP、事务等高级功能的扩展能力,必须设计 BeanPostProcessor 接口:citation:6citation:7
java
public interface BeanPostProcessor {
// 初始化前处理(如 @PostConstruct 执行)
default Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
// 初始化后处理(如 AOP 代理创建)
default Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
// 容器中的 BPP 注册与执行
public class DefaultBeanFactory extends AbstractBeanFactory {
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
public void addBeanPostProcessor(BeanPostProcessor bpp) {
beanPostProcessors.add(bpp);
}
private Object initializeBean(String beanName, Object bean, BeanDefinition bd) {
// 1. 执行 Aware 接口回调
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
// 2. BPP 前置处理
Object wrappedBean = bean;
for (BeanPostProcessor bpp : beanPostProcessors) {
wrappedBean = bpp.postProcessBeforeInitialization(wrappedBean, beanName);
}
// 3. 执行初始化方法(@PostConstruct、InitializingBean、init-method)
invokeInitMethods(wrappedBean, bd);
// 4. BPP 后置处理(AOP 代理在此创建!)
for (BeanPostProcessor bpp : beanPostProcessors) {
wrappedBean = bpp.postProcessAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
}
7. 第六步:容器启动入口
java
public class AnnotationConfigApplicationContext extends DefaultBeanFactory {
private ClassPathBeanDefinitionScanner scanner;
public AnnotationConfigApplicationContext(String... basePackages) {
// 1. 创建扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
// 2. 扫描并注册 BeanDefinition
scanner.scan(basePackages);
// 3. 预实例化所有非懒加载的单例 Bean
preInstantiateSingletons();
}
private void preInstantiateSingletons() {
for (String beanName : getBeanDefinitionNames()) {
BeanDefinition bd = getBeanDefinition(beanName);
if (bd.isSingleton() && !bd.isLazyInit()) {
getBean(beanName); // 触发创建
}
}
}
}
8. 完整使用示例
java
// 定义 Bean
@Component
public class UserDao {
public String findById(Long id) {
return "User-" + id;
}
}
@Component
public class UserService {
private final UserDao userDao;
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public String getUser(Long id) {
return userDao.findById(id);
}
}
// 启动容器
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext("com.example");
UserService userService = ctx.getBean(UserService.class);
System.out.println(userService.getUser(1L)); // User-1
}
}
9. 手写 IOC 与 Spring 的对比
| 功能维度 | 手写简易 IOC | Spring Framework |
|---|---|---|
| 配置方式 | 注解扫描 | XML、注解、JavaConfig、Groovy |
| BeanDefinition | 简化版 | RootBeanDefinition、GenericBeanDefinition 支持父子合并 |
| 作用域 | singleton、prototype | singleton、prototype、request、session、application、自定义 |
| 依赖注入 | 构造器 + 字段 | 构造器、Setter、字段、方法参数 |
| 循环依赖 | 三级缓存基础版 | 完整三级缓存 + @Lazy 支持 |
| AOP 支持 | 需手动扩展 BPP | AbstractAutoProxyCreator 原生支持 |
| 事件机制 | 无 | ApplicationEventPublisher + 观察者模式 |
| 国际化 | 无 | MessageSource |
| 资源加载 | 无 | ResourcePatternResolver |
| 类型转换 | 无 | PropertyEditor、Converter |
| 环境抽象 | 无 | Environment、Profile |
10. 生产环境避坑指南
-
10.1 构造器注入的循环依赖无法自动解决 手写容器时,如果 A 的构造器依赖 B,B 的构造器依赖 A,三级缓存机制在构造器注入阶段无法生效(因为对象尚未实例化完成,无法放入缓存)。解决方案:
- 改用字段注入(实例化后即可放入缓存);
- 引入
@Lazy注解,延迟注入其中一个依赖。
-
10.2 单例 Bean 的线程安全
singletonObjects必须使用ConcurrentHashMap,且getBean()的创建流程需要加锁(或使用synchronized块),防止并发环境下重复创建 Bean。 -
10.3 原型(Prototype)作用域的内存泄漏 Prototype Bean 不由容器管理生命周期,如果持有单例 Bean 的引用,且单例 Bean 持有 Prototype Bean 的引用,会导致 Prototype Bean 无法被 GC。应使用
ObjectFactory或@Lookup方法每次获取新实例。 -
10.4 包扫描的性能问题 大规模项目中,包扫描可能耗时较长。优化方案:
- 缩小扫描范围(精确指定包路径,不要用通配符);
- 引入索引文件(Spring 5+ 的
spring.components索引); - 延迟初始化非核心 Bean。
11. 面试官追问与高分回答模板
-
追问 1:"如何实现一个 IOC 容器?"
低分回答:"扫描包路径,用反射创建对象,然后字段注入。"(玩具级实现,没有工程思维)
高分回答:
"实现一个工程级 IOC 容器需要 5 个核心模块:
- 配置解析模块 :扫描指定包路径,识别
@Component等注解,将类信息解析为BeanDefinition(包含类名、作用域、依赖关系等元数据); - BeanDefinition 注册模块 :使用
Map<String, BeanDefinition>存储所有 Bean 定义,提供注册、查询、去重能力; - Bean 实例化模块 :根据
BeanDefinition通过反射调用构造器创建对象。支持构造器注入时,递归解析参数依赖; - 依赖注入模块 :实例化后,遍历
@Autowired字段,从容器中递归获取依赖对象并注入。使用三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)解决循环依赖; - 生命周期扩展模块 :定义
BeanPostProcessor接口,在 Bean 初始化前后提供扩展点,支持 AOP 代理创建、初始化方法执行等。
关键设计决策:单例池用ConcurrentHashMap、构造器注入优先、循环依赖检测用Set<String>标记创建中状态。"
- 配置解析模块 :扫描指定包路径,识别
-
追问 2:"为什么要设计 BeanDefinition?直接存 Class 对象不行吗?"
高分回答:
"
BeanDefinition是 IOC 容器的核心抽象,直接存 Class 对象无法满足以下需求:- 元数据丰富性:Class 对象只包含类信息,而 BeanDefinition 还存储作用域(singleton/prototype)、是否懒加载、初始化/销毁方法名、依赖关系、构造器参数等。这些信息无法从 Class 对象直接获取。
- 配置与实例解耦:容器启动时先加载所有 BeanDefinition(轻量级),再根据依赖关系按需或预加载实例(重量级)。如果直接存 Class,每次 getBean 都要重新解析注解,性能差且无法支持预加载。
- 父子 Bean 合并 :Spring 支持
<bean parent="parentBean">的继承关系,BeanDefinition 可以合并父定义的属性,Class 对象无法做到。 - 动态修改 :
BeanFactoryPostProcessor可以在 Bean 实例化前修改 BeanDefinition 的属性(如占位符替换),这是 Spring 扩展性的基础。
简单来说:Class 是 JVM 的类描述,BeanDefinition 是 Spring 的 Bean 配置描述,两者职责不同。"
-
追问 3:"三级缓存解决循环依赖的原理是什么?二级缓存够吗?"
高分回答:
"三级缓存的设计是为了同时解决循环依赖和 AOP 代理问题:
- 一级缓存
singletonObjects:存储完全初始化的 Bean,是成品池; - 二级缓存
earlySingletonObjects:存储提前暴露的半成品 Bean(已实例化但未注入属性); - 三级缓存
singletonFactories:存储ObjectFactory工厂,用于生成早期引用。
为什么二级缓存不够?
如果只有两级缓存,循环依赖时注入的早期引用和最终成品可能是不同的对象(比如 AOP 代理对象)。三级缓存中的ObjectFactory可以在需要时生成代理对象,确保早期引用和最终引用是同一个代理对象。
解决流程(A→B→A):
- 创建 A,实例化后将
ObjectFactory(包含 A 的原始对象)放入三级缓存; - A 注入 B,开始创建 B;
- B 实例化后需要注入 A,从三级缓存获取
ObjectFactory,生成 A 的早期引用(如果需要代理,这里生成代理对象); - B 完成初始化,放入一级缓存;
- A 继续注入 B(已完成),完成初始化,从三级缓存移入一级缓存。
如果只有两级缓存,步骤 3 中直接暴露原始对象,后续 A 初始化后的代理对象与早期引用不是同一个,导致 B 中的 A 和最终 A 不一致。"
- 一级缓存
-
追问 4:"构造器注入和字段注入在实现上有什么区别?"
高分回答:
"两者的核心区别在于依赖解析的时机:
- 构造器注入 :依赖在实例化阶段 就解析并注入。创建 Bean 时,通过反射获取构造器参数类型,递归调用
getBean()获取每个参数的依赖对象,然后调用Constructor.newInstance(args)创建对象。如果参数依赖存在循环依赖,此时对象尚未创建完成,无法放入缓存,导致构造器循环依赖无法自动解决。 - 字段注入 :先通过无参构造器(或默认构造器)创建对象,对象创建后立即放入三级缓存,然后再遍历
@Autowired字段,递归调用getBean()获取依赖并注入。因为对象已经创建并放入缓存,循环依赖时可以从缓存获取早期引用。
实现上的差异:构造器注入需要在instantiateBean()中解析参数,字段注入在populateBean()中解析字段。构造器注入更复杂,因为需要处理参数类型匹配、@Qualifier 指定、可变参数等问题。"
- 构造器注入 :依赖在实例化阶段 就解析并注入。创建 Bean 时,通过反射获取构造器参数类型,递归调用
-
追问 5:"如果容器中有两个同类型的 Bean,怎么决定注入哪一个?"
高分回答:
"处理同类型多实例的注入,需要实现类型匹配 + 名称匹配的两级策略:
- 按类型查找 :先根据字段类型从
beanDefinitionMap中筛选出所有匹配的 BeanDefinition; - 唯一性判断:如果只有一个匹配,直接注入;
- 按名称匹配:如果有多个匹配,检查字段名是否与某个 Bean 的名称一致,一致则注入该 Bean;
- @Qualifier 指定 :如果字段上有
@Qualifier("beanName"),直接按指定名称注入; - @Primary 优先 :检查匹配的 Bean 中是否有标记
@Primary的,优先注入; - 报错 :如果以上都无法确定唯一 Bean,抛出
NoUniqueBeanDefinitionException。
在手写容器中,至少需要实现前 4 步。Spring 还额外支持@Priority(JSR-250)、@Order等更复杂的优先级规则。"
- 按类型查找 :先根据字段类型从
-
追问 6:"BeanPostProcessor 的执行时机是什么?AOP 代理是在哪个阶段创建的?"
高分回答:
"
BeanPostProcessor在 Bean 生命周期的初始化阶段前后执行:postProcessBeforeInitialization:在 Bean 的初始化方法(@PostConstruct、InitializingBean.afterPropertiesSet()、init-method)之前 执行。典型应用是@PostConstruct注解的解析和执行。postProcessAfterInitialization:在 Bean 的初始化方法之后 执行。AOP 代理就是在这个阶段创建的!
AOP 代理创建时机 :Spring 的AbstractAutoProxyCreator(BPP 的实现类)在postProcessAfterInitialization中检查 Bean 是否需要代理(是否有切面匹配),如果需要,则创建 JDK 动态代理或 CGLIB 代理,将原始 Bean 包装为代理对象返回。
这意味着:AOP 代理是在 Bean 完全初始化之后创建的 ,所以@PostConstruct方法中调用同类方法不会触发 AOP(因为此时代理还未创建)。"
12. 方案选型速查表
| 场景 | 手写容器策略 | Spring 对应实现 |
|---|---|---|
| 单例管理 | ConcurrentHashMap 单例池 |
DefaultSingletonBeanRegistry |
| 循环依赖(字段注入) | 三级缓存 | DefaultSingletonBeanRegistry 三级缓存 |
| 循环依赖(构造器注入) | 无法自动解决,需 @Lazy |
@Lazy + ObjectFactory |
| AOP 代理 | BPP postProcessAfterInitialization |
AbstractAutoProxyCreator |
| 事务管理 | 自定义 BPP + 动态代理 | TransactionProxyFactoryBean |
| 配置解析 | 注解扫描 + 反射 | ClassPathBeanDefinitionScanner |
| 类型转换 | 手动 Converter |
ConversionService |
💡 面试官想要的满分总结:
手写 IOC 容器不是写玩具代码,而是检验对 Spring 设计思想的理解深度。
核心架构是 5 个模块 :配置解析 → BeanDefinition 注册 → Bean 实例化 → 依赖注入 → 生命周期扩展。
BeanDefinition是连接"配置"和"实例"的桥梁,解耦了元数据和对象,是 Spring 扩展性的基石。依赖注入的实现要区分构造器注入 (实例化时解析,循环依赖难解决)和字段注入 (实例化后注入,三级缓存可解决循环依赖)。三级缓存的设计精妙之处在于通过
ObjectFactory工厂延迟生成早期引用,确保 AOP 代理对象的一致性------二级缓存直接暴露原始对象会导致代理不一致。
BeanPostProcessor是容器扩展性的核心,AOP 代理在postProcessAfterInitialization阶段创建,这解释了为什么@PostConstruct中自调用不走 AOP。最后,手写容器时要关注线程安全 (
ConcurrentHashMap)、循环依赖检测 (singletonsCurrentlyInCreationSet)、同类型多实例的注入策略(类型 + 名称 + @Qualifier)。理解这些,才算真正理解了 Spring IOC 的精髓。
觉得对您有帮助,麻烦 点点关注啦 ,您的关注是我创作的最大动力~ 🎯