跳到正文
Elaine Blog
返回

手写最小 IoC 容器

Spring 生态与源码

最小 IoC 容器只需完成四步:注册对象配方、解析依赖、反射创建对象、缓存单例。亲手实现后,Spring 源码中的复杂类会落回这条主线。

Table of contents

Open Table of contents

运行最小容器

下载MiniApplicationContext 完整源码下载,运行:

mvn -Dtest=SpringSourceLabTest#miniContainerPerformsConstructorInjection test

测试注册接口实现和服务,再通过接口类型解析唯一候选:

MiniApplicationContext context = new MiniApplicationContext()
        .register(TestGreetingPort.class, GreetingService.class);

GreetingService service = context.getBean(GreetingService.class);

BeanDefinition 是创建配方

样例的 BeanDefinition 只保存 Java 类型。真实 Spring 还保存作用域、是否懒加载、工厂方法、构造参数、属性值、初始化和销毁方法等信息。

注册阶段不应立即执行业务构造器。先收集完整元数据,容器才能在实例化前运行工厂级扩展、校验覆盖关系并计算依赖。

递归解析构造器依赖

容器先选构造器,再逐个调用 getBean(parameterType) 获得依赖,最后反射执行构造器。样例支持唯一的可赋值候选;候选为 0 或多于 1 时给出明确错误。

真实实现还要处理构造器优先级、泛型、Qualifier、工厂 Bean、作用域和循环依赖。不要一次把全部能力塞入教学容器,否则会重新制造一份难读框架。

单例缓存避免重复创建

获取 Bean 时先查缓存;不存在才创建并保存。样例避免在 computeIfAbsent 内递归创建,因为嵌套修改同一 Map 会触发 ConcurrentModificationException。 生产容器还要保证并发安全,并记录“正在创建”状态来报告循环依赖。

给实验增加失败测试

依次验证:未注册依赖、多个接口实现、构造器抛异常、A→B→A 构造器循环。错误信息应包含请求类型和候选列表。失败路径比成功的 Hello World 更能解释容器边界。

下一步

阅读ApplicationContext 启动主线,观察 Spring 怎样把这个闭环扩展成 refresh() 模板流程。


分享这篇文章:

上一篇
IoC、DI 与 Spring 核心组件全景
下一篇
ApplicationContext 启动主线:读懂 refresh 模板流程