侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现自定义注解处理器完成依赖注入

2025-12-13 / 0 评论 / 4 阅读

题目

实现自定义注解处理器完成依赖注入

信息

  • 类型:问答
  • 难度:⭐⭐

考点

自定义注解定义,反射API应用,注解处理器设计,依赖注入原理

快速回答

实现步骤:

  1. 定义@Autowired注解标记需要注入的字段
  2. 创建BeanContainer管理所有Bean实例
  3. 通过反射扫描被@Component标记的类并实例化
  4. 遍历所有Bean的字段,检测@Autowired注解
  5. 从容器获取依赖对象并注入字段

关键点:

  • 使用Field.setAccessible(true)突破封装限制
  • 通过Class.getDeclaredFields()获取所有字段
  • 避免循环依赖使用构造器注入或检测机制
## 解析

原理说明

依赖注入(DI)是控制反转(IoC)的实现方式,通过反射动态解析类依赖关系并自动装配对象。核心流程:

  1. 定义注解标记组件和注入点
  2. 扫描类路径识别组件
  3. 实例化组件并存储到容器
  4. 解析依赖关系完成注入

代码示例

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();

最佳实践

  1. 循环依赖处理:使用三级缓存或setter注入解决
  2. 异常处理:明确抛出BeanCreationException包含根本原因
  3. 性能优化:缓存反射元数据避免重复解析
  4. 作用域控制:添加@Scope注解支持单例/原型模式

常见错误

错误类型后果解决方案
未设置field.setAccessible(true)IllegalAccessException确保突破封装限制
忽略循环依赖StackOverflowError使用构造器注入或依赖检测
未检查null依赖NullPointerException注入前验证依赖是否存在
混淆注解保留策略运行时找不到注解设置@Retention(RetentionPolicy.RUNTIME)

扩展知识

  • Spring框架实现:使用BeanPostProcessor处理注入,通过CGLIB代理增强功能
  • JSR-330标准:javax.inject包定义@Inject等通用注解
  • 方法注入:通过@Autowired标注方法实现更灵活的注入
  • Qualifier注解:解决同一接口多个实现类的歧义性问题