题目
实现自定义注解处理器完成依赖注入
信息
- 类型:问答
- 难度:⭐⭐
考点
自定义注解定义,反射API应用,注解处理器设计,依赖注入原理
快速回答
实现步骤:
- 定义
@Autowired注解标记需要注入的字段 - 创建
BeanContainer管理所有Bean实例 - 通过反射扫描被
@Component标记的类并实例化 - 遍历所有Bean的字段,检测
@Autowired注解 - 从容器获取依赖对象并注入字段
关键点:
- 使用
Field.setAccessible(true)突破封装限制 - 通过
Class.getDeclaredFields()获取所有字段 - 避免循环依赖使用构造器注入或检测机制
原理说明
依赖注入(DI)是控制反转(IoC)的实现方式,通过反射动态解析类依赖关系并自动装配对象。核心流程:
- 定义注解标记组件和注入点
- 扫描类路径识别组件
- 实例化组件并存储到容器
- 解析依赖关系完成注入
代码示例
1. 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {}2. 容器实现
public class BeanContainer {
private final Map<Class<?>, Object> beans = new HashMap<>();
public void register(Class<?> clazz) {
if (clazz.isAnnotationPresent(Component.class)) {
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
beans.put(clazz, instance);
} catch (Exception e) {
throw new RuntimeException("创建Bean失败: " + clazz.getName(), e);
}
}
}
public void injectDependencies() {
for (Object bean : beans.values()) {
for (Field field : bean.getClass().getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
Class<?> fieldType = field.getType();
Object dependency = beans.get(fieldType);
if (dependency == null) {
throw new RuntimeException("未找到依赖: " + fieldType.getName());
}
try {
field.setAccessible(true); // 突破private限制
field.set(bean, dependency);
} catch (IllegalAccessException e) {
throw new RuntimeException("注入失败", e);
}
}
}
}
}
}3. 使用示例
@Component
class ServiceA {
@Autowired
private ServiceB serviceB;
public void execute() {
serviceB.process();
}
}
@Component
class ServiceB {
public void process() {
System.out.println("Processing...");
}
}
// 启动容器
BeanContainer container = new BeanContainer();
container.register(ServiceA.class);
container.register(ServiceB.class);
container.injectDependencies();最佳实践
- 循环依赖处理:使用三级缓存或setter注入解决
- 异常处理:明确抛出BeanCreationException包含根本原因
- 性能优化:缓存反射元数据避免重复解析
- 作用域控制:添加@Scope注解支持单例/原型模式
常见错误
| 错误类型 | 后果 | 解决方案 |
|---|---|---|
| 未设置field.setAccessible(true) | IllegalAccessException | 确保突破封装限制 |
| 忽略循环依赖 | StackOverflowError | 使用构造器注入或依赖检测 |
| 未检查null依赖 | NullPointerException | 注入前验证依赖是否存在 |
| 混淆注解保留策略 | 运行时找不到注解 | 设置@Retention(RetentionPolicy.RUNTIME) |
扩展知识
- Spring框架实现:使用BeanPostProcessor处理注入,通过CGLIB代理增强功能
- JSR-330标准:javax.inject包定义@Inject等通用注解
- 方法注入:通过@Autowired标注方法实现更灵活的注入
- Qualifier注解:解决同一接口多个实现类的歧义性问题