可用轻量级map+自定义@component/@autowired注解模拟spring di,通过扫描包、实例化bean存入map、反射注入依赖、提供getbean接口,显性化实现ioc容器核心逻辑。

可以用一个轻量级的 Map + 自定义注解,模拟 Spring 的核心依赖注入(DI)思想,适合初学者理解“容器”“Bean 管理”“自动装配”等概念。关键不在于功能完整,而在于把控制反转(IoC)的逻辑显性化、可调试、可追踪。
1. 定义自己的 @Component 和 @Autowired 注解
先写两个最简注解,用 @Retention(RetentionPolicy.RUNTIME) 保证运行时能读取:
- @Component:标记哪些类要被容器管理(即成为 Bean);
- @Autowired:标记字段或构造器,表示“这里需要自动注入一个 Bean”。
注意:@Autowired 不强制要求 set 方法或 public 字段,用反射直接设值更贴近底层逻辑(初学建议从字段注入开始)。
2. 扫描包 + 实例化 Bean 放进 Map 容器
写一个简易的扫描器(比如用 ClassPathScanningCandidateComponentProvider 或手动遍历 classpath 下的 .class 文件),找到所有带 @Component 的类,然后:
- 用 Class.forName(...).getDeclaredConstructor().newInstance() 创建实例;
- 以类名首字母小写为 key(如 UserService → userService),实例为 value,存入 ConcurrentHashMap
; - 顺便缓存 Class → BeanName 映射,方便后续按类型查找。
3. 解析 @Autowired 并完成注入
遍历容器中所有 Bean 实例,对每个对象执行“属性注入”:
- 用 obj.getClass().getDeclaredFields() 拿到所有字段;
- 筛选出带 @Autowired 的字段;
- 根据字段类型(field.getType())去 Map 中找匹配的 Bean(支持接口类型注入,比如字段是 UserService 接口,就找实现了它的唯一实现类实例);
- 调用 field.setAccessible(true); field.set(obj, bean) 完成赋值。
⚠️ 注意:循环依赖此时会报错(如 A 依赖 B,B 又依赖 A),初学可先限制“只允许构造器注入单层依赖”,或加个正在创建中的 Set 做简单检测。
4. 提供 getBean() 方法并支持按类型/名称获取
对外暴露一个简易 API:
- getBean(String name):按 Bean 名称(如 "userService")取;
-
getBean(Class
type) :按类型取(需处理多个实现类时报错,或约定取第一个); - 可以加个 containsBean(String name) 方便调试。
这样你在 main 方法里就能写:MyApplicationContext ctx = new MyApplicationContext("com.example"); UserService us = ctx.getBean(UserService.class); —— 和 Spring 的体验几乎一致。
不复杂但容易忽略:注入顺序很重要。必须先确保所有 Bean 实例化完毕,再统一做属性注入;字段注入比构造器注入更容易实现,也更适合教学演示。











