2025年11月23日

[手写 MiniSpring 框架教程] 第 02 讲:IoC 容器基础

第 02 讲:IoC 容器基础

📖 本讲目标

  • 理解 IoC(控制反转)的本质
  • 设计 BeanFactory 核心接口
  • 实现 ApplicationContext 基础功能
  • 理解 Bean 的存储与管理机制

🎯 什么是 IoC?

IoC 的核心思想

IoC(Inversion of Control,控制反转) 是一种设计原则,它将对象的创建、依赖关系的管理从应用程序代码中转移到框架或容器中。

传统方式 vs IoC 方式

传统方式(控制权在程序员手中):

public class UserService {
    private UserRepository userRepository;

    public UserService() {
        // 程序员自己创建依赖对象
        this.userRepository = new UserRepository();
    }
}

IoC 方式(控制权在容器中):

@Component
public class UserService {
    @Autowired
    private UserRepository userRepository;
    // 容器负责创建和注入依赖
}

IoC 的优势

  1. 解耦:对象之间的依赖关系由容器管理,降低耦合度
  2. 灵活性:可以轻松替换实现类
  3. 可测试性:便于进行单元测试和模拟
  4. 统一管理:对象的生命周期由容器统一管理

🏗️ BeanFactory 接口设计

接口职责

BeanFactory 是 IoC 容器的核心接口,定义了访问容器中 Bean 的基本方法。

接口定义

创建 src/main/java/com/minispring/beans/factory/BeanFactory.java

package com.minispring.beans.factory;

/**
 * BeanFactory 接口
 * IoC 容器的核心接口,定义了访问容器中 Bean 的基本方法
 */
public interface BeanFactory {

    /**
     * 根据 Bean 名称获取 Bean 实例
     * @param name Bean 的名称
     * @return Bean 实例对象
     * @throws Exception 如果找不到指定名称的 Bean 或创建过程中发生异常
     */
    Object getBean(String name) throws Exception;

    /**
     * 根据 Bean 名称和指定类型获取 Bean 实例
     * @param name Bean 的名称
     * @param requiredType 期望的 Bean 类型
     * @param <T> Bean 的泛型类型
     * @return 指定类型的 Bean 实例
     * @throws Exception 如果找不到指定名称的 Bean 或类型不匹配
     */
    <T> T getBean(String name, Class<T> requiredType) throws Exception;

    /**
     * 根据类型获取 Bean 实例
     * @param requiredType Bean 的类型
     * @param <T> Bean 的泛型类型
     * @return 指定类型的 Bean 实例
     * @throws Exception 如果找不到指定类型的 Bean
     */
    <T> T getBean(Class<T> requiredType) throws Exception;

    /**
     * 判断容器中是否包含指定名称的 Bean
     * @param name Bean 的名称
     * @return 如果存在返回 true,否则返回 false
     */
    boolean containsBean(String name);

    /**
     * 判断指定名称的 Bean 是否为单例模式
     * @param name Bean 的名称
     * @return 如果是单例返回 true,否则返回 false
     */
    boolean isSingleton(String name);

    /**
     * 判断指定名称的 Bean 是否为原型模式
     * @param name Bean 的名称
     * @return 如果是原型返回 true,否则返回 false
     */
    boolean isPrototype(String name);

    /**
     * 获取指定名称 Bean 的类型
     * @param name Bean 的名称
     * @return Bean 的 Class 类型
     */
    Class<?> getType(String name);
}

接口方法说明

  1. getBean(String name):最基本的 Bean 获取方法
  2. getBean(String name, Class):带类型检查的获取方法
  3. getBean(Class):按类型获取,支持自动匹配
  4. containsBean(String):检查 Bean 是否存在
  5. isSingleton/isPrototype:查询 Bean 的作用域
  6. getType(String):获取 Bean 的类型信息

🏭 ApplicationContext 核心实现

设计思路

ApplicationContextBeanFactory 的实现类,也是整个框架的核心。它需要:

  1. 存储 Bean 定义:使用 Map 存储 BeanDefinition
  2. 缓存单例 Bean:使用 Map 缓存已创建的单例 Bean
  3. 管理 Bean 生命周期:创建、初始化、销毁

基础实现

创建 src/main/java/com/minispring/context/ApplicationContext.java

package com.minispring.context;

import com.minispring.beans.factory.BeanFactory;
import com.minispring.beans.factory.config.BeanDefinition;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 应用上下文,IoC 容器的核心实现
 */
public class ApplicationContext implements BeanFactory {

    // ==================== 核心存储结构 ====================

    /**
     * 存储所有 BeanDefinition(Bean 的元数据)
     * Key: beanName, Value: BeanDefinition
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /**
     * 单例 Bean 缓存池(一级缓存)
     * Key: beanName, Value: Bean 实例
     */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    /**
     * 正在创建中的 Bean 集合,用于检测循环依赖
     */
    private final Set<String> singletonsCurrentlyInCreation = ConcurrentHashMap.newKeySet();

    // ==================== BeanDefinition 管理 ====================

    /**
     * 注册 BeanDefinition
     * @param beanName Bean 名称
     * @param beanDefinition Bean 定义
     */
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        if (beanDefinitionMap.containsKey(beanName)) {
            throw new RuntimeException("Bean 名称重复: " + beanName);
        }
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    /**
     * 获取 BeanDefinition
     * @param beanName Bean 名称
     * @return BeanDefinition
     */
    public BeanDefinition getBeanDefinition(String beanName) {
        return beanDefinitionMap.get(beanName);
    }

    // ==================== Bean 获取(核心方法) ====================

    @Override
    public Object getBean(String beanName) throws Exception {
        // 1. 获取 BeanDefinition
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) {
            throw new RuntimeException("找不到 Bean: " + beanName);
        }

        // 2. 根据作用域决定返回策略
        if (beanDefinition.isSingleton()) {
            // 单例模式:从缓存获取或创建
            return getSingleton(beanName, beanDefinition);
        } else {
            // 原型模式:每次都创建新实例
            return createBean(beanName, beanDefinition);
        }
    }

    @Override
    public <T> T getBean(String beanName, Class<T> requiredType) throws Exception {
        Object bean = getBean(beanName);
        if (requiredType != null && !requiredType.isInstance(bean)) {
            throw new RuntimeException("Bean 类型不匹配: " + beanName);
        }
        return (T) bean;
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws Exception {
        // 遍历所有 BeanDefinition,查找类型匹配的 Bean
        String matchedBeanName = null;

        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();

            if (requiredType.isAssignableFrom(beanDefinition.getBeanClass())) {
                if (matchedBeanName != null) {
                    throw new RuntimeException("找到多个类型为 " + requiredType.getName() +
                            " 的 Bean: " + matchedBeanName + ", " + beanName);
                }
                matchedBeanName = beanName;
            }
        }

        if (matchedBeanName == null) {
            throw new RuntimeException("找不到类型为 " + requiredType.getName() + " 的 Bean");
        }

        return getBean(matchedBeanName, requiredType);
    }

    @Override
    public boolean containsBean(String beanName) {
        return beanDefinitionMap.containsKey(beanName);
    }

    @Override
    public boolean isSingleton(String name) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null) {
            throw new RuntimeException("找不到 Bean: " + name);
        }
        return beanDefinition.isSingleton();
    }

    @Override
    public boolean isPrototype(String name) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null) {
            throw new RuntimeException("找不到 Bean: " + name);
        }
        return beanDefinition.isPrototype();
    }

    @Override
    public Class<?> getType(String name) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(name);
        if (beanDefinition == null) {
            throw new RuntimeException("找不到 Bean: " + name);
        }
        return beanDefinition.getBeanClass();
    }

    // ==================== 单例 Bean 管理 ====================

    /**
     * 获取单例 Bean(从缓存或创建)
     * @param beanName Bean 名称
     * @param beanDefinition Bean 定义
     * @return Bean 实例
     */
    private Object getSingleton(String beanName, BeanDefinition beanDefinition) throws Exception {
        synchronized (singletonObjects) {
            // 1. 先从缓存中获取
            Object singletonObject = singletonObjects.get(beanName);
            if (singletonObject != null) {
                return singletonObject;
            }

            // 2. 创建 Bean 实例
            singletonObject = createBean(beanName, beanDefinition);

            // 3. 放入缓存
            singletonObjects.put(beanName, singletonObject);

            return singletonObject;
        }
    }

    // ==================== Bean 创建 ====================

    /**
     * 创建 Bean 实例(核心流程)
     * @param beanName Bean 名称
     * @param bd Bean 定义
     * @return Bean 实例
     */
    private Object createBean(String beanName, BeanDefinition bd) throws Exception {
        // 1. 检查循环依赖
        if (singletonsCurrentlyInCreation.contains(beanName)) {
            throw new RuntimeException("检测到循环依赖: " + beanName);
        }

        // 2. 标记为正在创建
        singletonsCurrentlyInCreation.add(beanName);

        try {
            // 3. 使用反射创建实例(暂时使用无参构造函数)
            Object bean = bd.getBeanClass().getDeclaredConstructor().newInstance();

            // TODO: 后续将实现依赖注入和初始化回调

            return bean;

        } finally {
            // 4. 移除创建中标记
            singletonsCurrentlyInCreation.remove(beanName);
        }
    }

    // ==================== 辅助方法 ====================

    /**
     * 获取所有 Bean 名称
     * @return Bean 名称集合
     */
    public Set<String> getBeanDefinitionNames() {
        return beanDefinitionMap.keySet();
    }

    /**
     * 获取 Bean 数量
     * @return Bean 数量
     */
    public int getBeanDefinitionCount() {
        return beanDefinitionMap.size();
    }
}

📦 BeanDefinition 基础

在实现完整的 BeanDefinition 之前,我们先创建一个简化版本:

创建 src/main/java/com/minispring/beans/factory/config/BeanDefinition.java

package com.minispring.beans.factory.config;

/**
 * BeanDefinition 类
 * 存储 Bean 的元数据信息,是 IoC 容器管理 Bean 的核心数据结构
 */
public class BeanDefinition {

    // Bean 的 Class 类型,用于反射创建实例
    private Class<?> beanClass;

    // Bean 在容器中的唯一名称
    private String beanName;

    // Bean 的作用域:singleton(单例)或 prototype(原型)
    private String scope = "singleton"; // 默认单例

    /**
     * 构造函数
     */
    public BeanDefinition() {
    }

    /**
     * 构造函数
     * @param beanClass Bean 的 Class 类型
     */
    public BeanDefinition(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    // ==================== Getter 和 Setter 方法 ====================

    public Class<?> getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    /**
     * 判断是否为单例模式
     * @return true 表示单例
     */
    public boolean isSingleton() {
        return "singleton".equals(scope);
    }

    /**
     * 判断是否为原型模式
     * @return true 表示原型
     */
    public boolean isPrototype() {
        return "prototype".equals(scope);
    }
}

🧪 简单测试

创建一个简单的测试类验证基础功能:

package com.minispring.demo;

import com.minispring.beans.factory.config.BeanDefinition;
import com.minispring.context.ApplicationContext;

public class SimpleTest {
    public static void main(String[] args) throws Exception {
        ApplicationContext context = new ApplicationContext();

        // 手动注册一个 Bean
        BeanDefinition bd = new BeanDefinition();
        bd.setBeanClass(String.class);
        bd.setBeanName("testBean");
        bd.setScope("singleton");

        context.registerBeanDefinition("testBean", bd);

        // 获取 Bean
        Object bean = context.getBean("testBean");
        System.out.println("获取到 Bean: " + bean);
        System.out.println("Bean 类型: " + context.getType("testBean"));
        System.out.println("是否为单例: " + context.isSingleton("testBean"));
    }
}

📝 本讲总结

本讲我们完成了:

  1. ✅ 理解了 IoC 的核心思想
  2. ✅ 设计了 BeanFactory 核心接口
  3. ✅ 实现了 ApplicationContext 基础功能
  4. ✅ 创建了 BeanDefinition 数据结构
  5. ✅ 实现了单例 Bean 的缓存机制
  6. ✅ 实现了循环依赖检测的基础框架

🎯 关键点回顾

  1. IoC 容器:负责管理对象的创建和生命周期
  2. BeanFactory:定义了容器的基本操作接口
  3. ApplicationContext:容器的核心实现
  4. BeanDefinition:存储 Bean 的元数据信息
  5. 单例缓存:使用 Map 缓存单例 Bean,提高性能

🚀 下一讲预告

在下一讲中,我们将完善 BeanDefinition 的设计,并实现 Bean 的注册机制,包括:

  • BeanDefinition 的完整属性
  • Bean 名称生成策略
  • Bean 注册流程

准备好了吗?让我们继续 第 03 讲:Bean 定义与注册


思考题

  1. 为什么使用 ConcurrentHashMap 而不是普通的 HashMap?
  2. 单例 Bean 缓存的作用是什么?
  3. 循环依赖检测是如何工作的?

“以书为舟,遨游尘世”,
最好的免费 kindle 电子书分享站:

You may also like...

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注


*