java中可手写简易di容器:通过@component标记组件、@autowired注入依赖、@singleton控制单例,利用反射扫描类、实例化bean并自动装配,体现di核心原理。

Java中可以用注解配合反射机制手写一个简易的依赖注入(DI)容器,核心是识别@Component、@Autowired等自定义或标准注解,扫描类、实例化 Bean、自动装配依赖。不需要 Spring,但能体现 DI 的基本原理。
定义关键注解
先创建几个轻量级注解,用于标记组件和注入点:
- @Component:标记可被容器管理的类(类似 Spring 的 @Component)
- @Autowired:标记需要自动注入的字段(支持 by-type,默认不支持 by-name)
- @Singleton(可选):标识该 Bean 应为单例(否则每次 getBean 都新建)
示例定义:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component { }
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired { }
扫描并注册 Bean
启动时扫描指定包路径下所有带有 @Component 的类,用反射获取其 Class 对象,并缓存到 Map 中(如 Map<class>, Object></class>)。
- 用
ClassLoader.getResources()或第三方工具(如 ClassGraph)获取 class 文件路径 - 遍历每个 .class 文件,用
Class.forName()加载类,检查是否含@Component - 对每个匹配类,调用
clazz.getDeclaredConstructor().newInstance()创建实例 - 若类标有
@Singleton,则只创建一次并复用;否则每次 getBean 都新建(prototype 模式)
执行依赖注入(Autowired)
对每个已创建的 Bean 实例,遍历其所有声明字段,检查是否有 @Autowired 注解:
- 获取字段类型(
field.getType()),在已注册的 Bean Map 中查找匹配类型的实例 - 若找到且字段为 private,需调用
field.setAccessible(true)才能赋值 - 调用
field.set(instance, dependency)完成注入 - 注意循环依赖:简易容器通常不处理,遇到正在创建中的 Bean 可抛异常或跳过
建议在 Bean 实例化后统一执行注入,避免部分字段未就绪。
提供对外使用的容器接口
封装一个简单容器类(如 SimpleContainer),暴露常用方法:
-
void scan(String packageName):启动扫描与初始化 -
<t> T getBean(Class<t> type)</t></t>:按类型获取 Bean(支持泛型) -
<t> T getBean(String name)</t>(可选):按名称获取(需额外维护 name → instance 映射)
使用示例:
SimpleContainer container = new SimpleContainer();
container.scan("com.example.service");
UserService service = container.getBean(UserService.class); // 自动注入了 UserRepository
不复杂但容易忽略细节:字段注入需处理访问权限、单例生命周期、类加载器隔离、泛型擦除影响类型匹配等。这个简易容器适合教学或嵌入式场景,生产环境仍推荐 Spring 或 Micronaut 等成熟框架。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











