前言

在Spring框架中,IoC(控制反转)AOP(面向切面编程) 是两大核心特性。很多开发者每天都在使用Spring,却对IoC容器的内部实现原理一知半解。你是否想过:Spring是如何管理Bean的?为什么我们不再需要手动new对象了?Bean工厂到底做了什么?

本文将从零开始,带你手写实现一个简易的IoC容器,深入理解Spring的核心原理。通过一步步的设计和代码实现,你将彻底掌握Bean工厂、Bean定义、Bean注册等核心概念,为后续学习Spring源码打下坚实基础。


目录


一、IoC核心概念分析

1. Spring的核心是什么

在Spring框架中,最核心的两个特性就是 IoCAOP。本文我们将重点剖析IoC的实现原理。

Spring核心架构

2. IoC的四个关键问题

2.1 IoC是什么?

IoC(Inversion of Control),即控制反转。简单来说:依赖对象的获得被翻转了

传统开发模式中,我们需要自己创建依赖对象:

// 传统方式:手动创建依赖对象
UserService userService = new UserService();
UserDao userDao = new UserDao();
userService.setUserDao(userDao);

使用IoC后,对象由容器创建和管理:

// IoC方式:从容器获取对象
UserService userService = (UserService) context.getBean("userService");

IoC概念图

2.2 IoC有什么好处?

IoC带来的三大核心优势:

  1. 代码更简洁:不需要手动new对象,减少样板代码
  2. 解耦更彻底:面向接口编程,使用者与具体实现解耦,易于扩展和替换
  3. AOP支持:IoC为AOP提供了基础,方便进行横切关注点的编程

IoC优势

2.3 IoC容器做什么?

IoC容器的核心职责:

  • 创建 Bean实例
  • 管理 Bean的生命周期
  • 提供 Bean实例给使用者

IoC容器职责

2.4 IoC容器与工厂模式

是的!IoC容器本质上就是工厂模式的实现。IoC容器负责创建对象实例,使用者通过getBean方法获取。因此,IoC容器也被称为Bean工厂

工厂模式

关键概念Bean = 组件 = 类的对象实例


二、IoC容器实现

通过上述分析,我们明确了IoC的核心是Bean工厂。下面让我们一步步实现它。

1. Bean工厂的作用

Bean工厂的三大核心职责:

  • 创建Bean
  • 管理Bean
  • 对外提供Bean实例

Bean工厂作用

2. Bean工厂初步设计

基于Bean工厂的职责,我们来分析它应该具备的行为:

Bean工厂设计

首先,Bean工厂需要对外提供获取Bean实例的方法,因此需要定义 getBean() 方法。同时,工厂需要知道要生产的Bean类型,所以getBean方法需要接受参数,返回类型用Object表示:

public interface BeanFactory {
    Object getBean(String beanName);
}

Bean工厂接口

核心问题:Bean工厂如何知道要创建什么对象?如何创建?

Bean工厂问题

解决方案:

  1. 定义一个模型来表示如何创建Bean实例的信息Bean定义
  2. Bean工厂提供接收Bean定义信息的行为 → 注册机制

3. Bean定义详解

3.1 BeanDefinition的作用

告诉Bean工厂如何创建某个类的Bean实例

3.2 获取Bean实例的方式

获取Bean实例方式

主要有两种方式:

  • 通过构造方法反射创建
  • 通过工厂方法创建
3.3 BeanDefinition需要提供的信息

BeanDefinition信息

核心信息包括:

  • Bean的Class类型
  • Scope(作用域:单例/原型)
  • 工厂Bean名称和工厂方法名称
  • 初始化方法和销毁方法
3.4 BeanDefinition接口实现

完整代码如下:

/**
 * Bean定义接口
 */
public interface BeanDefinition {

    String SCOPE_SINGLETION = "singleton";
    String SCOPE_PROTOTYPE = "prototype";

    /**
     * 获取Bean的Class类型
     */
    Class<?> getBeanClass();

    /**
     * 获取作用域
     */
    String getScope();

    /**
     * 是否单例
     */
    boolean isSingleton();

    /**
     * 是否原型
     */
    boolean isPrototype();

    /**
     * 工厂Bean名称
     */
    String getFactoryBeanName();

    /**
     * 工厂方法名称
     */
    String getFactoryMethodName();

    /**
     * 初始化方法名称
     */
    String getInitMethodName();

    /**
     * 销毁方法名称
     */
    String getDestroyMethodName();

    /**
     * 是否主要候选Bean
     */
    boolean isPrimary();

    /**
     * 校验Bean定义的合法性
     */
    default boolean validate() {
        // 没定义class,工厂bean或工厂方法没指定,则不合法
        if (this.getBeanClass() == null) {
            if (StringUtils.isBlank(getFactoryBeanName()) || StringUtils.isBlank(getFactoryMethodName())) {
                return false;
            }
        }

        // 定义了类,又定义工厂bean,不合法
        if (this.getBeanClass() != null && StringUtils.isNotBlank(getFactoryBeanName())) {
            return false;
        }

        return true;
    }
}

同时创建通用实现类 GenericBeanDefinition

public class GenericBeanDefinition implements BeanDefinition {
    private Class<?> beanClass;
    private String scope = SCOPE_SINGLETION;
    private String factoryBeanName;
    private String factoryMethodName;
    private String initMethodName;
    private String destroyMethodName;
    private boolean primary = false;
    
    // getter和setter方法省略...
}

4. Bean注册机制

BeanDefinition定义好后,需要将其注册到Bean工厂。为此,我们定义 BeanDefinitionRegistry 接口:

Bean注册

4.1 BeanDefinitionRegistry接口设计

需要具备两大功能:

  1. 注册BeanDefinition
  2. 获取BeanDefinition

为保证能区分每个BeanDefinition,需要为每个Bean定义唯一名称。

BeanDefinitionRegistry

代码实现:

public interface BeanDefinitionRegistry {

    /**
     * 注册Bean定义
     */
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 
        throws BeanDefinitionRegistException;

    /**
     * 获取Bean定义
     */
    BeanDefinition getBeanDefinition(String beanName);

    /**
     * 是否包含指定Bean定义
     */
    boolean containsBeanDefinition(String beanName);
}

5. BeanFactory核心实现

5.1 DefaultBeanFactory功能清单

目前的设计架构:

IoC架构

DefaultBeanFactory 需要实现的5大功能:

  1. 实现Bean定义信息的注册
  2. 实现getBean方法
  3. 实现初始化方法的执行
  4. 实现单例管理
  5. 实现容器关闭时执行销毁操作

DefaultBeanFactory

思考:对于单例Bean,可否提前实例化?(预实例化策略)

预实例化


三、IoC容器增强

基础版IoC容器实现后,我们继续增强其功能。

1. Bean别名机制

Bean除了唯一名称外,还可以有别名。别名特点:

  • 可以有多个别名
  • 别名也可以有别名
  • 别名也是唯一的

实现时需要考虑:

  1. 数据结构:如何存储名称与别名的映射关系
  2. 功能点:如何解析别名获取真实Bean名称

Bean别名

具体实现留给读者自行完成。

2. 按Type获取Bean

除了通过Bean名称获取实例,还需要支持按类型获取Bean

2.1 扩展接口
public interface BeanFactory {
    Object getBean(String beanName);
    
    // 新增:按类型获取Bean
    <T> T getBean(Class<T> requiredType);
}
2.2 实现思路

朴素实现方式:

按Type获取Bean

遍历所有Bean定义,找到类型匹配的Bean。但这种方式性能较差

优化方案:提前构建Type与Bean名称的映射关系,用Map缓存:

private Map<Class<?>, Set<String>> typeMap = new ConcurrentHashMap<>(256);
2.3 buildTypeMap方法实现

在DefaultBeanFactory中添加类型映射构建方法:

buildTypeMap

核心逻辑:

  1. 遍历所有Bean定义
  2. 获取Bean的Class类型及其所有父类和接口
  3. 建立Class → Set的映射关系
  4. 处理一个Class对应多个Bean的情况(通过@Primary注解)

Type映射逻辑

2.4 完整流程
  1. 在BeanFactory中添加 getType() 方法,封装获取Bean类型的逻辑
  2. 实现 buildTypeMap() 构建类型映射
  3. 实现 getBean(Class<T>) 方法
  4. 处理一个类型对应多个Bean的情况(通过Primary判断)

四、总结

本文从零开始,一步步实现了Spring IoC容器的核心功能。让我们回顾一下关键知识点:

核心要点

  1. IoC本质:控制反转,将对象的创建和管理交给容器

  2. 核心组件

    • BeanFactory:Bean工厂接口,提供获取Bean的方法
    • BeanDefinition:Bean定义,描述如何创建Bean实例
    • BeanDefinitionRegistry:Bean定义注册表,管理Bean定义
    • DefaultBeanFactory:默认实现,整合上述功能
  3. 关键特性

    • 单例管理:容器级别的单例缓存
    • 生命周期:初始化方法和销毁方法
    • 别名机制:Bean可以有多个别名
    • 按类型获取:支持通过Class类型获取Bean

架构图

最终的IoC容器核心类图:

IoC核心类图

后续学习建议

  • 深入阅读Spring源码,对比本文的简化实现
  • 学习BeanPostProcessor机制,理解Bean的后置处理
  • 研究循环依赖的解决方式
  • 扩展AOP功能,实现完整的Spring核心

如果本文对你有帮助,欢迎点赞、收藏、关注!有问题欢迎评论区留言讨论~

关键词:Spring IoC, 控制反转, Bean工厂, 手写Spring, 源码解析, Java, 框架原理

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐