Java可通过注解+反射实现轻量级自定义DI容器:用@MyComponent标记Bean类,@MyAutowired标记注入点,扫描包路径、实例化Bean并反射注入依赖,支持字段与构造器注入及简单循环依赖检测。

Java 中可以通过注解 + 反射手写一个轻量级的自定义 DI 容器,核心思路是:用自定义注解标记需要被注入的字段或构造器,启动时扫描类、实例化 Bean、再通过反射将依赖对象设进去。
定义关键注解
先创建几个必要注解,语义清晰、保留到运行时:
- @MyComponent:标记可被容器管理的类(类似 @Component)
- @MyAutowired:标记需要自动注入的字段或构造参数(类似 @Autowired)
- @MyQualifier(可选):用于按名称区分同类型多个 Bean
示例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyComponent { }
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired { }
扫描并注册 Bean
启动时扫描指定包路径下所有带 @MyComponent 的类,用 ClassLoader 加载类,然后缓存其 Class 对象或直接 newInstance(注意无参构造要求):
立即学习“Java免费学习笔记(深入)”;
- 递归遍历 classpath 下的 .class 文件或使用 org.reflections 库简化扫描
- 对每个匹配类,调用
clazz.getDeclaredConstructor().newInstance()创建实例 - 把实例存入 Map<Class<?>, Object> 或 Map<String, Object>(key 可用类名或 @MyQualifier 值)
执行依赖注入
对每个已创建的 Bean 实例,遍历其所有声明字段(含 private),检查是否有 @MyAutowired 注解:
- 获取字段类型
field.getType(),去 Bean 容器中查找匹配类型的实例 - 若找到且字段为 private,调用
field.setAccessible(true)破除访问限制 - 调用
field.set(instance, dependency)完成赋值 - 支持构造器注入:优先找带 @MyAutowired 的构造器,按参数类型从容器取 Bean 后 newInstance
注意循环依赖场景需加简单检测(如正在创建中的标志位),否则会栈溢出。
使用示例与收尾
写两个类:
@MyComponent
public class UserService { ... }
@MyComponent
public class UserController {
@MyAutowired
private UserService service; // 自动注入
}
启动时调用 MyApplicationContext.init("com.example"),之后可通过 context.getBean(UserController.class) 获取已注入完成的实例。
这个简易 DI 不含 AOP、作用域、懒加载等高级特性,但能跑通核心流程,适合理解 Spring 底层原理或嵌入小型项目。


















