如何写一个简单的IoC容器实现依赖注入?

wen java案例 64

本文目录导读:

如何写一个简单的IoC容器实现依赖注入?

  1. 核心概念
  2. 最简实现
  3. 使用示例
  4. 增强版本
  5. 完整的实战示例
  6. 关键设计要点

我来教你实现一个简单的IoC容器,从基础到逐步完善,我会用Java语言演示,因为它的反射机制最清晰。

核心概念

IoC容器的三个核心功能:

  1. 注册:告诉容器哪些类需要管理
  2. 解析:分析类之间的依赖关系
  3. 注入:自动创建依赖实例

最简实现

先从一个基础版本开始:

import java.lang.reflect.Field;
import java.util.*;
// 注解:标记需要注入的字段
@interface Inject {
}
// 简单IoC容器
class SimpleContainer {
    // 存储已注册的类和对应的实例
    private Map<Class<?>, Object> instances = new HashMap<>();
    // 注册接口与实现类
    public <T> void register(Class<T> interfaceClass, T implementation) {
        instances.put(interfaceClass, implementation);
    }
    // 获取bean实例(自动注入依赖)
    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> clazz) throws Exception {
        // 如果已有实例,直接返回
        if (instances.containsKey(clazz)) {
            return (T) instances.get(clazz);
        }
        // 创建新实例
        T instance = clazz.getDeclaredConstructor().newInstance();
        instances.put(clazz, instance);
        // 注入依赖
        injectDependencies(instance);
        return instance;
    }
    // 注入依赖
    private void injectDependencies(Object instance) throws Exception {
        Class<?> clazz = instance.getClass();
        // 遍历所有字段
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Inject.class)) {
                field.setAccessible(true);
                // 获取依赖的类型
                Class<?> fieldType = field.getType();
                // 递归获取依赖实例
                Object dependency = getBean(fieldType);
                field.set(instance, dependency);
            }
        }
    }
}

使用示例

// 定义接口和类
interface Database {
    void query(String sql);
}
class MySQLDatabase implements Database {
    @Override
    public void query(String sql) {
        System.out.println("MySQL执行: " + sql);
    }
}
class UserService {
    @Inject  // 标记需要注入
    private Database database;
    public void findUser(int id) {
        database.query("SELECT * FROM users WHERE id = " + id);
    }
}
// 使用容器
public class Main {
    public static void main(String[] args) throws Exception {
        SimpleContainer container = new SimpleContainer();
        // 注册数据库实现
        container.register(Database.class, new MySQLDatabase());
        // 获取UserService(自动注入Database)
        UserService userService = container.getBean(UserService.class);
        userService.findUser(1);
    }
}

增强版本

添加更多功能:

import java.lang.reflect.Constructor;
import java.util.*;
// 支持单例和原型模式
enum Scope {
    SINGLETON,  // 单例
    PROTOTYPE   // 原型(每次新建)
}
// 增强的容器
class AdvancedContainer {
    // 存储单例实例
    private Map<Class<?>, Object> singletons = new HashMap<>();
    // 存储Bean定义
    private Map<Class<?>, BeanDefinition> beanDefinitions = new HashMap<>();
    // Bean定义
    static class BeanDefinition {
        Class<?> clazz;
        Scope scope = Scope.SINGLETON;
        BeanDefinition(Class<?> clazz) {
            this.clazz = clazz;
        }
    }
    // 注册类
    public void register(Class<?> clazz) {
        beanDefinitions.put(clazz, new BeanDefinition(clazz));
    }
    // 注册并指定作用域
    public void register(Class<?> clazz, Scope scope) {
        BeanDefinition def = new BeanDefinition(clazz);
        def.scope = scope;
        beanDefinitions.put(clazz, def);
    }
    // 获取Bean
    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> clazz) throws Exception {
        BeanDefinition def = beanDefinitions.get(clazz);
        if (def == null) {
            throw new IllegalArgumentException("Bean not registered: " + clazz);
        }
        // 单例模式
        if (def.scope == Scope.SINGLETON) {
            if (!singletons.containsKey(clazz)) {
                singletons.put(clazz, createInstance(clazz));
            }
            return (T) singletons.get(clazz);
        }
        // 原型模式
        return (T) createInstance(clazz);
    }
    // 创建实例并注入依赖
    private Object createInstance(Class<?> clazz) throws Exception {
        // 查找合适的构造器
        Constructor<?> constructor = findConstructor(clazz);
        Object instance;
        if (constructor != null) {
            // 通过构造器注入
            Class<?>[] paramTypes = constructor.getParameterTypes();
            Object[] params = new Object[paramTypes.length];
            for (int i = 0; i < paramTypes.length; i++) {
                params[i] = getBean(paramTypes[i]);
            }
            instance = constructor.newInstance(params);
        } else {
            // 使用默认构造器
            instance = clazz.getDeclaredConstructor().newInstance();
        }
        // 字段注入
        injectFields(instance);
        return instance;
    }
    // 查找带@Inject注解的构造器
    private Constructor<?> findConstructor(Class<?> clazz) {
        for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
            if (constructor.isAnnotationPresent(Inject.class)) {
                return constructor;
            }
        }
        return null;
    }
    // 字段注入
    private void injectFields(Object instance) throws Exception {
        Class<?> clazz = instance.getClass();
        for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Inject.class)) {
                field.setAccessible(true);
                Object dependency = getBean(field.getType());
                field.set(instance, dependency);
            }
        }
    }
}

完整的实战示例

// 演示基于接口的编程
interface Logger {
    void log(String message);
}
class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[Console] " + message);
    }
}
// 使用构造器注入
class OrderService {
    private final Logger logger;
    private final Database database;
    @Inject  // 标记构造器注入
    public OrderService(Logger logger, Database database) {
        this.logger = logger;
        this.database = database;
    }
    public void createOrder(String orderId) {
        logger.log("Creating order: " + orderId);
        database.query("INSERT INTO orders VALUES ('" + orderId + "')");
        logger.log("Order created successfully");
    }
}
// 测试
public class Demo {
    public static void main(String[] args) throws Exception {
        AdvancedContainer container = new AdvancedContainer();
        // 注册组件
        container.register(ConsoleLogger.class);
        container.register(MySQLDatabase.class);
        container.register(OrderService.class);
        // 创建服务(依赖自动注入)
        OrderService orderService = container.getBean(OrderService.class);
        orderService.createOrder("ORD-001");
    }
}

关键设计要点

  1. 类型识别:使用Class<?>作为键来标识和管理Bean
  2. 依赖解析:通过反射分析构造器参数和字段
  3. 生命周期管理:区分单例和原型模式
  4. 循环依赖处理:可以通过三级缓存解决(Spring的方案)

这个实现虽然简单,但包含了IoC容器的核心思想,实际生产中可以借鉴Spring的实现思路,添加更多功能如AOP、配置文件支持等。

抱歉,评论功能暂时关闭!