文章目录
- [507. Java 反射 - 在 BeanFactory 中实现依赖注入](#507. Java 反射 - 在 BeanFactory 中实现依赖注入)
-
- [1. 什么是依赖注入?](#1. 什么是依赖注入?)
- [2. 定义 @Inject 注解](#2. 定义 @Inject 注解)
- [3. 示例:应用类依赖 DBService](#3. 示例:应用类依赖 DBService)
- [4. BeanFactory 的依赖注入逻辑](#4. BeanFactory 的依赖注入逻辑)
- [5. 使用效果](#5. 使用效果)
- [6. 要点 🎓](#6. 要点 🎓)
507. Java 反射 - 在 BeanFactory 中实现依赖注入
1. 什么是依赖注入?
在企业应用中,类往往不是孤立的,它们依赖于其他服务。例如:
MyApplication依赖于DBService。- 一个业务逻辑类可能依赖多个工具类(如日志、消息队列、配置服务)。
👉 如果由开发者手动 new 出这些依赖对象,代码会非常耦合 ,难以维护和测试。
👉 依赖注入 (DI) 的思想就是:对象不自己创建依赖,而是由 容器/工厂 负责初始化并注入。
这就是 Spring 框架的核心思想之一 ,我们这里通过 BeanFactory 实现一个简化版。
2. 定义 @Inject 注解
我们先定义一个标记注解,用来告诉工厂哪些字段需要被注入:
java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Inject {
}
这样工厂在扫描类时,就知道该字段需要自动赋值。
3. 示例:应用类依赖 DBService
java
@Singleton
public class MyApplication {
@Inject
private DBService dbService;
public boolean isDBServiceSet() {
return dbService != null;
}
}
说明:
MyApplication标记为 单例。dbService字段使用@Inject标记,意味着 由工厂负责赋值。- 应用启动时,工厂会帮我们把
DBService实例注入到dbService中。
4. BeanFactory 的依赖注入逻辑
在 instantiateBeanClass() 方法中,添加了对字段的扫描和赋值逻辑:
java
private <T> T instantiateBeanClass(Class<T> beanClass, Object[] arguments)
throws NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
// 1. 通过构造器创建 bean 实例
Class<?>[] argumentsClasses =
Arrays.stream(arguments).map(Object::getClass).toArray(Class<?>[]::new);
Constructor<T> beanConstructor = beanClass.getConstructor(argumentsClasses);
T bean = beanConstructor.newInstance(arguments);
// 2. 获取所有字段,筛选出带有 @Inject 的字段
Field[] injectableFields = Arrays.stream(beanClass.getDeclaredFields())
.filter(field -> field.isAnnotationPresent(Inject.class))
.toArray(Field[]::new);
// 3. 为每个需要注入的字段创建实例并赋值
for (Field injectableField : injectableFields) {
Class<?> fieldClass = injectableField.getType();
Object fieldValue = BeanFactory.INSTANCE.getInstanceOf(fieldClass);
injectableField.setAccessible(true); // 无视 private 修饰符
injectableField.set(bean, fieldValue);
}
return bean;
}
5. 使用效果
java
void main() {
BeanFactory beanFactory = BeanFactory.INSTANCE;
MyApplication app = beanFactory.getInstanceOf(MyApplication.class);
IO.println("App has been created with a DBService: " + app.isDBServiceSet());
}
运行结果:
java
App has been created with a DBService: true
说明:
BeanFactory自动创建了DBService实例。- 通过
@Inject,它被赋值到MyApplication的dbService字段。 - 我们无需手动
new DBService(),解耦了应用类和依赖对象的关系。
6. 要点 🎓
- 解耦 :MyApplication 不关心
DBService如何创建,只关心它能否被注入。 - 自动化 :以后要替换
DBService实现,只需修改工厂逻辑或注解,不影响应用类。 - 对比 Spring :Spring 的
@Autowired与我们自定义的@Inject类似,只是功能更强大(支持构造函数注入、方法注入、Qualifier 等)。 - 局限性 :目前的实现只支持 字段注入,不支持构造函数或方法注入,但已经能展示 DI 的核心思想。