sanguispring:我的简易版 Spring IoC 容器 从源码到发布
—— 从源码到发布的学习之旅
作者:三桂 日期:2025-05-30
一、背景与动机
在学习 Spring 框架的过程中,IoC(控制反转)与依赖注入(DI)一直是最核心、也最玄妙的部分。虽然大量现成框架能帮我们快速上手,但要真正理解它的内部原理,最有效的方式就是“手写”一个最简化版本。
于是,我决定从零开始,手写一个——sanguispring,它既能帮我巩固反射、XML 解析与设计模式等基础知识,也能在完成后有一个可展示的开源项目,记录我的学习轨迹。
二、核心实现概览
1. 项目结构
com.sangui.sanguispring.core
├── ApplicationContext.java # 容器顶层接口
└── ClassPathXmlApplicationContext.java # XML 加载与属性注入实现
示例 Bean 与测试:
com.sangui.bean.Vip.java
com.sangui.dao.OrderDao.java
com.sangui.service.OrderService.java
com.sangui.test.SanguiTest.java
配置文件:
src/main/resources/sanguispring.xml2. ApplicationContext 接口
public interface ApplicationContext {
Object getBean(String name);
}定义最简的
getBean(String)方法,用于按 ID 返回单例 Bean。
3. ClassPathXmlApplicationContext 实现
主要步骤:
解析 XML:用 dom4j 读取
sanguispring.xml,提取所有<bean>节点。实例化 Bean:反射调用无参构造器,放入
singletonMap。属性注入:遍历每个
<property>,根据value与ref属性,调用对应的 setter 方法。支持 16 种简单类型及其包装类型:
boolean/Boolean、byte/Byte、short/Short、int/Integer、long/Long、float/Float、double/Double、char/Character。其他类型默认当作
String处理。
switch (field.getType().getSimpleName()) {
case "int":
setMethod.invoke(bean, Integer.parseInt(value));
break;
// ……
default:
setMethod.invoke(bean, value);
}三、演示示例
配置文件 sanguispring.xml:
<beans>
<bean id="vip" class="com.sangui.bean.Vip">
<property name="name" value="lisi"/>
<property name="age" value="44"/>
<property name="height" value="1.77"/>
</bean>
<bean id="orderDao" class="com.sangui.dao.OrderDao"/>
<bean id="orderService" class="com.sangui.service.OrderService">
<property name="orderDao" ref="orderDao"/>
</bean>
</beans>测试代码 SanguiTest.java:
ApplicationContext ctx = new ClassPathXmlApplicationContext("sanguispring.xml");
OrderService service = (OrderService) ctx.getBean("orderService");
System.out.println(service);
service.save();
Vip vip = (Vip) ctx.getBean("vip");
System.out.println(vip);运行结果:
OrderService{orderDao=com.sangui.dao.OrderDao@6d06d69c}
数据库正在新增用户!!
Vip{name='lisi', age=44, height=1.77}
四、局限与思考
sanguispring 目前只是一个学习原型,主要存在以下不足:
仅支持属性注入,不支持构造器注入或复杂注入逻辑。
只支持简单类型(及包装类型)注入,对数组、集合、枚举、甚至
Date等类型都无能为力。无循环依赖检测与解决,存在循环引用时容易出现 NPE 或 StackOverflowError。
所有 Bean 都为单例,无作用域(prototype、request 等)概念。
异常处理粗糙,反射或加载出错时只打印堆栈,无自定义异常或友好提示。
无生命周期钩子、无 AOP 支持,离完整框架仍有较大差距。
这些痛点正是我下一步要钻研和改进的方向,比如加入构造器注入、支持集合注入、实现 BeanPostProcessor、AOP 拦截等。
五、开源发布
将代码托管在 GitHub: https://github.com/Wusangui571/sanguispring
提交
README.md、LICENSE(MIT),并附上使用示例、TODO 列表。构建一个可发布的 Jar:
mvn clean package发布到 GitHub Releases 或私服,方便下载;也可以改造为 Maven Central 坐标。
六、总结与展望
从最初的“手写一个 IoC 容器”想法,到如今能解析 XML、反射注入,整个过程让我深刻理解了 Spring 容器的核心机制。未来,我计划逐步将 sanguispring 打造成支持:
注解驱动的配置(
@Component、@Autowired)构造器注入与多构造重载选择
Bean 生命周期回调与后处理器
AOP 切面编程支持
扩展作用域管理(prototype、request、session)
更完备的异常与日志体系
欢迎大家在 GitHub 上提出 Issue、PR,一起交流、一起进步!
免 责 声 明
- 微信
- 赶快加我聊天吧

- 赶快加我聊天吧
