手写 Spring 框架之依赖注入(DI):从原理到实现,彻底搞懂 IoC 容器核心

关键词:Spring 源码, 依赖注入, DI, IoC 容器, 手写框架, 循环依赖, Java 反射


写在前面

在学习 Spring 框架的过程中,很多人都有这样一个困惑:每天都在使用 @Autowired@Resource 进行依赖注入,但 Spring 到底是如何实现依赖注入的?构造注入和 Setter 注入有什么区别?循环依赖又是如何解决的?

本文将带你从零开始手写 Spring 的依赖注入功能,通过实际编码深入理解 Spring IoC 容器的核心原理。读完本文,你将能够:

  • ✅ 理解依赖注入的本质和实现方式
  • ✅ 手写实现构造器注入和属性注入
  • ✅ 掌握循环依赖的检测与处理机制
  • ✅ 深入理解 Spring Bean 的生命周期

目录


一、DI 依赖注入概述

1.1 什么是依赖注入

DI(Dependency Injection,依赖注入) 是 Spring 框架的核心概念之一。它指的是由容器在运行期动态地将某个依赖注入到对象之中

简单来说:给 Bean 对象的成员变量赋值

传统方式 vs 依赖注入

// 传统方式:自己创建依赖
public class Girl {
    private Boy boyfriend = new Boy();  // 自己创建
}

// 依赖注入:由容器注入
public class Girl {
    private Boy boyfriend;  // 容器注入
    
    // 通过构造器注入
    public Girl(Boy boyfriend) {
        this.boyfriend = boyfriend;
    }
}

1.2 依赖注入的本质

依赖注入的本质是 “赋值”,具体分为两种:

  1. 给构造方法参数赋值(构造器注入)
  2. 给属性赋值(属性注入/Setter 注入)

1.3 依赖注入的分类

依赖的来源
来源类型说明示例
构造参数依赖通过构造方法传入public Girl(String name, Boy boy)
属性依赖通过字段注入private Boy boyfriend;
值的类型
值类型说明示例
直接值基本数据类型、String"小丽", 20, 'C'
Bean 依赖引用其他 Beannew Boy()
集合类型数组、List、Set、MapList<Boy>, Map<String, Object>

复杂情况示例

public class Girl {
    public Girl(String name, int age, char cup, Boy boyfriend) {
        // 直接值 + Bean 依赖混合
    }
    
    private List<Boy> boyFriends;  // 集合中存储 Bean 依赖
    private Map<String, Object> attributes;  // Map 中存储混合类型
}

二、构造器注入实现

2.1 构造器注入分析

在非 IoC 场景下,我们创建对象时直接传入参数即可:

public static void main(String[] args) {
    Boy boy = new Boy();
    Girl girl = new Girl("小丽", 20, 'C', boy);
}

但在 IoC 容器中,我们需要通过反射来创建对象,这就要求我们能够获取到构造参数的依赖信息。

构造参数依赖的特点

  • 数量:参数个数不确定
  • 顺序:参数顺序必须匹配
  • 类型:可能是直接值或 Bean 引用

2.2 BeanReference 设计

为了区分直接值Bean 依赖,我们设计 BeanReference 类:

/**
 * Bean 引用
 * 用于表示一个属性或参数依赖另一个 Bean
 */
public class BeanReference {
    private String beanName;  // 按名称依赖
    private Class<?> beanType;  // 按类型依赖
    
    public BeanReference(String beanName) {
        this.beanName = beanName;
    }
    
    public BeanReference(Class<?> beanType) {
        this.beanType = beanType;
    }
    
    // getters...
}

使用示例

// 区分直接值和 Bean 依赖
List<Object> args = new ArrayList<>();
args.add("小丽");  // 直接值:String
args.add(20);  // 直接值:int
args.add('C');  // 直接值:char
args.add(new BeanReference("boy"));  // Bean 依赖

判断逻辑

if (obj instanceof BeanReference) {
    // 是 Bean 依赖,需要从容器中获取
    BeanReference ref = (BeanReference) obj;
    realValue = getBean(ref.getBeanName());
} else {
    // 是直接值,直接使用
    realValue = obj;
}

复杂情况处理

// 集合中包含 Bean 依赖
List<Object> boyFriends = new ArrayList<>();
boyFriends.add(new BeanReference("boy1"));
boyFriends.add(new BeanReference("boy2"));

// 需要遍历集合,将 BeanReference 替换为实际 Bean
for (int i = 0; i < boyFriends.size(); i++) {
    if (boyFriends.get(i) instanceof BeanReference) {
        boyFriends.set(i, getBean(((BeanReference) boyFriends.get(i)).getBeanName()));
    }
}

2.3 构造器注入核心实现

BeanDefinition 扩展
public interface BeanDefinition {
    // ... 其他方法
    
    /**
     * 获取构造参数值
     */
    List<?> getConstructorArgumentValues();
    
    /**
     * 设置构造参数值
     */
    void setConstructorArgumentValues(List<?> constructorArgumentValues);
}
默认实现
public class GenericBeanDefinition implements BeanDefinition {
    private Class<?> beanClass;
    private List<?> constructorArgumentValues;  // 构造参数值
    private String factoryBeanName;
    private String factoryMethodName;
    
    // 缓存构造方法或工厂方法(避免重复推断)
    private Constructor<?> constructor;
    private Method factoryMethod;
    
    @Override
    public List<?> getConstructorArgumentValues() {
        return constructorArgumentValues;
    }
    
    @Override
    public void setConstructorArgumentValues(List<?> constructorArgumentValues) {
        this.constructorArgumentValues = constructorArgumentValues;
    }
    
    // ... getters/setters
}
BeanFactory 实现
public class DefaultBeanFactory implements BeanFactory {
    
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private ThreadLocal<Set<String>> buildingBeans = new ThreadLocal<>();  // 记录正在创建的 Bean
    
    @Override
    public Object getBean(String beanName) throws Exception {
        return doGetBean(beanName);
    }
    
    private Object doGetBean(String beanName) throws Exception {
        // 1. 从单例缓存中获取
        Object bean = singletonObjects.get(beanName);
        if (bean != null) {
            return bean;
        }
        
        // 2. 检查循环依赖
        if (isBuilding(beanName)) {
            throw new Exception("检测到循环依赖: " + beanName);
        }
        
        // 3. 标记开始创建
        markBuilding(beanName);
        
        try {
            // 4. 获取 BeanDefinition
            BeanDefinition bd = beanDefinitionMap.get(beanName);
            if (bd == null) {
                throw new Exception("Bean not found: " + beanName);
            }
            
            // 5. 创建实例
            Object instance = createBeanInstance(bd);
            
            // 6. 属性注入
            setPropertyDIValues(bd, instance);
            
            // 7. 初始化
            doInit(bd, instance);
            
            // 8. 缓存单例
            if (bd.isSingleton()) {
                singletonObjects.put(beanName, instance);
            }
            
            return instance;
        } finally {
            // 9. 移除创建标记
            unmarkBuilding(beanName);
        }
    }
    
    /**
     * 创建 Bean 实例
     */
    private Object createBeanInstance(BeanDefinition bd) throws Exception {
        // 有构造参数,通过构造器创建
        if (bd.getConstructorArgumentValues() != null && !bd.getConstructorArgumentValues().isEmpty()) {
            return createInstanceByConstructor(bd);
        }
        
        // 无参构造
        return bd.getBeanClass().newInstance();
    }
    
    /**
     * 通过构造器创建实例
     */
    private Object createInstanceByConstructor(BeanDefinition bd) throws Exception {
        // 1. 获取构造参数的真实值(解析 BeanReference)
        Object[] args = getConstructorArgumentValues(bd);
        
        // 2. 获取匹配的构造方法
        Constructor<?> constructor = determineConstructor(bd, args);
        
        // 3. 缓存构造方法
        bd.setConstructor(constructor);
        
        // 4. 通过反射创建实例
        return constructor.newInstance(args);
    }
    
    /**
     * 解析构造参数值
     * 将 BeanReference 替换为实际的 Bean
     */
    private Object[] getConstructorArgumentValues(BeanDefinition bd) throws Exception {
        List<?> args = bd.getConstructorArgumentValues();
        if (args == null || args.isEmpty()) {
            return null;
        }
        
        Object[] realArgs = new Object[args.size()];
        for (int i = 0; i < args.size(); i++) {
            realArgs[i] = getRealValue(args.get(i));
        }
        return realArgs;
    }
    
    /**
     * 获取真实值
     */
    private Object getRealValue(Object value) throws Exception {
        if (value instanceof BeanReference) {
            // Bean 依赖,递归获取
            BeanReference ref = (BeanReference) value;
            if (ref.getBeanName() != null) {
                return getBean(ref.getBeanName());
            }
            // 按类型获取...
        }
        return value;
    }
    
    /**
     * 推断构造方法
     */
    private Constructor<?> determineConstructor(BeanDefinition bd, Object[] args) throws Exception {
        // 1. 如果已经缓存,直接返回
        if (bd.getConstructor() != null) {
            return bd.getConstructor();
        }
        
        // 无参数,返回无参构造
        if (args == null || args.length == 0) {
            return bd.getBeanClass().getConstructor();
        }
        
        // 2. 根据参数类型精确匹配
        Class<?>[] paramTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            paramTypes[i] = args[i].getClass();
        }
        
        Constructor<?> constructor = null;
        try {
            constructor = bd.getBeanClass().getConstructor(paramTypes);
        } catch (NoSuchMethodException e) {
            // 精确匹配失败,继续模糊匹配
        }
        
        // 3. 模糊匹配:遍历所有构造方法
        if (constructor == null) {
            outer:
            for (Constructor<?> ct : bd.getBeanClass().getConstructors()) {
                Class<?>[] parameterTypes = ct.getParameterTypes();
                if (parameterTypes.length == args.length) {
                    for (int i = 0; i < parameterTypes.length; i++) {
                        // 检查类型是否兼容(考虑继承关系)
                        if (!parameterTypes[i].isAssignableFrom(args[i].getClass())) {
                            continue outer;
                        }
                    }
                    constructor = ct;
                    break;
                }
            }
        }
        
        if (constructor == null) {
            throw new Exception("找不到匹配的构造方法: " + bd.getBeanClass());
        }
        
        return constructor;
    }
    
    // ========== 循环依赖检测 ==========
    
    private boolean isBuilding(String beanName) {
        Set<String> buildingSet = buildingBeans.get();
        return buildingSet != null && buildingSet.contains(beanName);
    }
    
    private void markBuilding(String beanName) {
        Set<String> buildingSet = buildingBeans.get();
        if (buildingSet == null) {
            buildingSet = new HashSet<>();
            buildingBeans.set(buildingSet);
        }
        buildingSet.add(beanName);
    }
    
    private void unmarkBuilding(String beanName) {
        Set<String> buildingSet = buildingBeans.get();
        if (buildingSet != null) {
            buildingSet.remove(beanName);
        }
    }
}
使用示例
// 1. 创建容器
DefaultBeanFactory factory = new DefaultBeanFactory();

// 2. 注册 CBean
GenericBeanDefinition cBeanDef = new GenericBeanDefinition();
cBeanDef.setBeanClass(CBean.class);
factory.registerBeanDefinition("cbean", cBeanDef);

// 3. 注册 ABean,带有构造参数依赖
GenericBeanDefinition aBeanDef = new GenericBeanDefinition();
aBeanDef.setBeanClass(ABean.class);

// 设置构造参数
List<Object> args = new ArrayList<>();
args.add("abean01");  // 直接值
args.add(new BeanReference("cbean"));  // Bean 依赖

aBeanDef.setConstructorArgumentValues(args);
factory.registerBeanDefinition("abean", aBeanDef);

// 4. 获取 Bean
ABean aBean = (ABean) factory.getBean("abean");
aBean.doSomething();

2.4 循环依赖问题

什么是循环依赖
public class A {
    public A(B b) {}  // A 依赖 B
}

public class B {
    public B(A a) {}  // B 依赖 A
}

这种情况下,创建 A 需要 B,创建 B 又需要 A,形成死循环。

循环依赖的三种情况
┌─────┐      ┌─────┐
│  A  │ ───> │  B  │
└─────┘      └─────┘
   ▲            │
   └────────────┘
   
情况1:构造器循环依赖(无法解决)

┌─────┐      ┌─────┐
│  A  │ ───> │  B  │
└─────┘      └─────┘
                │
                ▼
             ┌─────┐
             │  C  │
             └─────┘
                │
                ▼
             ┌─────┐
             │  A  │
             └─────┘
             
情况2:多例循环依赖(无法解决)

┌─────┐      ┌─────┐
│  A  │ ───> │  B  │
└─────┘      └─────┘
   ▲            │
   └────────────┘
   
情况3:属性循环依赖(可以解决)
构造器循环依赖的检测
// 使用 ThreadLocal 记录正在创建的 Bean
private ThreadLocal<Set<String>> buildingBeans = new ThreadLocal<>();

private Object doGetBean(String beanName) throws Exception {
    // 检查循环依赖
    if (isBuilding(beanName)) {
        throw new Exception("检测到循环依赖: " + beanName);
    }
    
    // 标记开始创建
    markBuilding(beanName);
    
    try {
        // 创建 Bean...
    } finally {
        // 移除标记
        unmarkBuilding(beanName);
    }
}

构造器循环依赖无法解决,因为构造器注入要求在实例化时就提供所有依赖,而依赖又需要被依赖对象先创建完成。


三、属性注入实现

3.1 属性注入分析

属性注入是通过 setter 方法或直接反射给字段赋值。

public class Girl {
    private String name;
    private int age;
    private char cup;
    private List<Boy> boyFriends;
    
    // setter 方法...
}

3.2 PropertyValue 设计

/**
 * 属性值
 * 记录属性名和对应的值
 */
public class PropertyValue {
    private String name;  // 属性名
    private Object value;  // 属性值(可能是直接值或 BeanReference)
    
    public PropertyValue(String name, Object value) {
        this.name = name;
        this.value = value;
    }
    
    // getters...
}

3.3 属性注入核心实现

BeanDefinition 扩展
public interface BeanDefinition {
    // ... 其他方法
    
    /**
     * 获取属性值列表
     */
    List<PropertyValue> getPropertyValues();
    
    /**
     * 设置属性值
     */
    void setPropertyValues(List<PropertyValue> propertyValues);
}
BeanFactory 实现
public class DefaultBeanFactory implements BeanFactory {
    
    // 提前暴露正在创建的 Bean(用于解决循环依赖)
    private ThreadLocal<Map<String, Object>> earlyExposeBeans = new ThreadLocal<>();
    
    private Object doGetBean(String beanName) throws Exception {
        // 1. 从单例缓存获取
        Object bean = singletonObjects.get(beanName);
        if (bean != null) {
            return bean;
        }
        
        // 2. 从提前暴露缓存获取(解决循环依赖)
        bean = getEarlyExposeBean(beanName);
        if (bean != null) {
            return bean;
        }
        
        // 3. 检查循环依赖
        if (isBuilding(beanName)) {
            throw new Exception("检测到循环依赖: " + beanName);
        }
        
        markBuilding(beanName);
        
        try {
            BeanDefinition bd = beanDefinitionMap.get(beanName);
            
            // 4. 创建实例(此时还未注入属性)
            Object instance = createBeanInstance(bd);
            
            // 5. 提前暴露实例(解决属性循环依赖)
            if (bd.isSingleton()) {
                doEarlyExpose(beanName, instance);
            }
            
            // 6. 属性注入
            setPropertyDIValues(bd, instance);
            
            // 7. 初始化
            doInit(bd, instance);
            
            // 8. 缓存到单例池
            if (bd.isSingleton()) {
                singletonObjects.put(beanName, instance);
                removeEarlyExpose(beanName);
            }
            
            return instance;
        } finally {
            unmarkBuilding(beanName);
        }
    }
    
    /**
     * 属性注入
     */
    private void setPropertyDIValues(BeanDefinition bd, Object instance) throws Exception {
        List<PropertyValue> propertyValues = bd.getPropertyValues();
        if (propertyValues == null || propertyValues.isEmpty()) {
            return;
        }
        
        for (PropertyValue pv : propertyValues) {
            if (StringUtils.isBlank(pv.getName())) {
                continue;
            }
            
            // 通过反射获取字段
            Field field = instance.getClass().getDeclaredField(pv.getName());
            field.setAccessible(true);  // 暴力访问 private 字段
            
            // 获取真实值(解析 BeanReference)
            Object realValue = getRealValue(pv.getValue());
            
            // 设置值
            field.set(instance, realValue);
        }
    }
    
    /**
     * 提前暴露 Bean
     */
    private void doEarlyExpose(String beanName, Object instance) {
        Map<String, Object> earlyMap = earlyExposeBeans.get();
        if (earlyMap == null) {
            earlyMap = new HashMap<>();
            earlyExposeBeans.set(earlyMap);
        }
        earlyMap.put(beanName, instance);
    }
    
    private Object getEarlyExposeBean(String beanName) {
        Map<String, Object> earlyMap = earlyExposeBeans.get();
        return earlyMap != null ? earlyMap.get(beanName) : null;
    }
}
使用示例
// 1. 创建容器
DefaultBeanFactory factory = new DefaultBeanFactory();

// 2. 注册 Boy
GenericBeanDefinition boyDef = new GenericBeanDefinition();
boyDef.setBeanClass(Boy.class);
List<PropertyValue> boyProps = new ArrayList<>();
boyProps.add(new PropertyValue("name", "小明"));
boyDef.setPropertyValues(boyProps);
factory.registerBeanDefinition("boy", boyDef);

// 3. 注册 Girl,属性注入
GenericBeanDefinition girlDef = new GenericBeanDefinition();
girlDef.setBeanClass(Girl.class);
List<PropertyValue> girlProps = new ArrayList<>();
girlProps.add(new PropertyValue("name", "小丽"));
girlProps.add(new PropertyValue("age", 20));
girlProps.add(new PropertyValue("boyfriend", new BeanReference("boy")));
girlDef.setPropertyValues(girlProps);
factory.registerBeanDefinition("girl", girlDef);

// 4. 获取 Bean
Girl girl = (Girl) factory.getBean("girl");
System.out.println(girl.getName());  // 小丽
System.out.println(girl.getBoyfriend().getName());  // 小明

3.4 属性注入的循环依赖解决

为什么属性注入可以解决循环依赖?
// 非 IoC 场景下很容易解决
Boy b = new Boy();
Girl g = new Girl();
b.setGirl(g);
g.setBoy(b);

关键点:分步骤创建对象

  1. 先创建对象(此时属性为 null)
  2. 再注入属性
提前暴露机制
// 创建流程:
// 1. 实例化 A(调用构造器)
A a = new A();
// 2. 提前暴露 A(放入缓存)
earlyExposeBeans.put("a", a);
// 3. 注入 A 的属性(发现依赖 B)
//    -> 创建 B
//       -> 实例化 B
//       -> 提前暴露 B
//       -> 注入 B 的属性(发现依赖 A)
//          -> 从提前暴露缓存获取 A(半成品)
//       -> B 创建完成
//    -> 设置 A.b = B
// 4. A 创建完成

核心代码

private Object doGetBean(String beanName) throws Exception {
    // 先从提前暴露缓存获取
    Object bean = getEarlyExposeBean(beanName);
    if (bean != null) {
        return bean;
    }
    
    // 创建实例
    Object instance = createBeanInstance(bd);
    
    // 提前暴露(解决循环依赖的关键)
    if (bd.isSingleton()) {
        doEarlyExpose(beanName, instance);
    }
    
    // 属性注入
    setPropertyDIValues(bd, instance);
    
    return instance;
}

四、完整实现与测试

完整类图

┌─────────────────────────────────────────────────────────────┐
│                         BeanFactory                          │
│  + getBean(String): Object                                  │
│  + registerBeanDefinition(String, BeanDefinition): void     │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                    DefaultBeanFactory                        │
│                                                              │
│  - beanDefinitionMap: Map<String, BeanDefinition>           │
│  - singletonObjects: Map<String, Object>                    │
│  - buildingBeans: ThreadLocal<Set<String>>                  │
│  - earlyExposeBeans: ThreadLocal<Map<String, Object>>       │
│                                                              │
│  + doGetBean(String): Object                                │
│  + createBeanInstance(BeanDefinition): Object               │
│  + setPropertyDIValues(BeanDefinition, Object): void        │
│  + determineConstructor(BeanDefinition, Object[]): Constructor│
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                       BeanDefinition                         │
│  + getBeanClass(): Class<?>                                 │
│  + getConstructorArgumentValues(): List<?>                  │
│  + getPropertyValues(): List<PropertyValue>                 │
│  + isSingleton(): boolean                                   │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│                  GenericBeanDefinition                       │
│  - beanClass: Class<?>                                      │
│  - constructorArgumentValues: List<?>                       │
│  - propertyValues: List<PropertyValue>                      │
│  - singleton: boolean                                       │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      BeanReference                           │
│  - beanName: String                                         │
│  - beanType: Class<?>                                       │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      PropertyValue                           │
│  - name: String                                             │
│  - value: Object                                            │
└─────────────────────────────────────────────────────────────┘

测试用例

public class DITest {
    
    @Test
    public void testConstructorDI() throws Exception {
        DefaultBeanFactory factory = new DefaultBeanFactory();
        
        // 注册 CBean
        GenericBeanDefinition cDef = new GenericBeanDefinition();
        cDef.setBeanClass(CBean.class);
        cDef.setPropertyValues(Arrays.asList(
            new PropertyValue("name", "CBean")
        ));
        factory.registerBeanDefinition("cbean", cDef);
        
        // 注册 ABean,构造器注入
        GenericBeanDefinition aDef = new GenericBeanDefinition();
        aDef.setBeanClass(ABean.class);
        aDef.setConstructorArgumentValues(Arrays.asList(
            "abean01",
            new BeanReference("cbean")
        ));
        factory.registerBeanDefinition("abean", aDef);
        
        // 获取并测试
        ABean aBean = (ABean) factory.getBean("abean");
        assertNotNull(aBean);
        assertEquals("abean01", aBean.getName());
        assertNotNull(aBean.getCBean());
        assertEquals("CBean", aBean.getCBean().getName());
    }
    
    @Test
    public void testPropertyDI() throws Exception {
        DefaultBeanFactory factory = new DefaultBeanFactory();
        
        // 注册 Boy
        GenericBeanDefinition boyDef = new GenericBeanDefinition();
        boyDef.setBeanClass(Boy.class);
        boyDef.setPropertyValues(Arrays.asList(
            new PropertyValue("name", "小明")
        ));
        factory.registerBeanDefinition("boy", boyDef);
        
        // 注册 Girl,属性注入
        GenericBeanDefinition girlDef = new GenericBeanDefinition();
        girlDef.setBeanClass(Girl.class);
        girlDef.setPropertyValues(Arrays.asList(
            new PropertyValue("name", "小丽"),
            new PropertyValue("age", 20),
            new PropertyValue("boyfriend", new BeanReference("boy"))
        ));
        factory.registerBeanDefinition("girl", girlDef);
        
        // 获取并测试
        Girl girl = (Girl) factory.getBean("girl");
        assertNotNull(girl);
        assertEquals("小丽", girl.getName());
        assertEquals(20, girl.getAge());
        assertNotNull(girl.getBoyfriend());
        assertEquals("小明", girl.getBoyfriend().getName());
    }
    
    @Test
    public void testCircularDependency() throws Exception {
        DefaultBeanFactory factory = new DefaultBeanFactory();
        
        // A 依赖 B
        GenericBeanDefinition aDef = new GenericBeanDefinition();
        aDef.setBeanClass(A.class);
        aDef.setPropertyValues(Arrays.asList(
            new PropertyValue("b", new BeanReference("b"))
        ));
        factory.registerBeanDefinition("a", aDef);
        
        // B 依赖 A
        GenericBeanDefinition bDef = new GenericBeanDefinition();
        bDef.setBeanClass(B.class);
        bDef.setPropertyValues(Arrays.asList(
            new PropertyValue("a", new BeanReference("a"))
        ));
        factory.registerBeanDefinition("b", bDef);
        
        // 获取 A(循环依赖应该被解决)
        A a = (A) factory.getBean("a");
        assertNotNull(a);
        assertNotNull(a.getB());
        assertNotNull(a.getB().getA());
        assertEquals(a, a.getB().getA());  // 是同一个 A
    }
}

五、总结与思考

核心知识点回顾

1. 依赖注入的本质

  • 给 Bean 的成员变量赋值
  • 构造器注入:通过构造方法参数赋值
  • 属性注入:通过反射给字段赋值

2. BeanReference 设计

  • 区分直接值和 Bean 依赖
  • 支持按名称或按类型依赖
  • 递归解析 Bean 依赖

3. 构造器注入实现

  • 存储构造参数(List)
  • 推断匹配的构造方法
  • 处理构造参数中的 BeanReference

4. 属性注入实现

  • PropertyValue 封装属性和值
  • 反射设置字段值
  • 提前暴露解决循环依赖

5. 循环依赖处理

  • 构造器循环依赖:无法解决(实例化时需要完整依赖)
  • 属性循环依赖:可以解决(提前暴露半成品对象)

与 Spring 源码的对比

功能手写实现Spring 源码
BeanReferenceBeanReferenceRuntimeBeanReference
属性封装PropertyValuePropertyValue
构造器推断简单遍历匹配ConstructorResolver(复杂算法)
循环依赖简单提前暴露三级缓存(singletonFactories、earlySingletonObjects、singletonObjects)
代理支持AOP 代理对象提前暴露

学习建议

  1. 动手实践:自己实现一遍,加深理解
  2. 对比源码:与 Spring 源码对比,学习优化技巧
  3. 思考问题
    • 为什么构造器注入无法解决循环依赖?
    • 提前暴露为什么能解决属性循环依赖?
    • Spring 的三级缓存是如何工作的?
  4. 扩展练习
    • 支持注解配置(@Autowired@Value
    • 实现 Setter 方法注入
    • 实现 AOP 代理功能

扩展作业

条件依赖配置支持

在 Bean 定义配置中可以指定它条件依赖某些 Bean 或类,当这些 Bean 或类存在时,这个 Bean 的配置才能生效。

// 示例:只有当 DataSource Bean 存在时,才创建 JdbcTemplate
GenericBeanDefinition jdbcTemplateDef = new GenericBeanDefinition();
jdbcTemplateDef.setBeanClass(JdbcTemplate.class);
jdbcTemplateDef.setDependsOn("dataSource");  // 条件依赖
factory.registerBeanDefinition("jdbcTemplate", jdbcTemplateDef);

相关资源

  • Spring 官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html
  • Spring 源码:https://github.com/spring-projects/spring-framework
  • 相关书籍:《Spring 源码深度解析》、《Spring 技术内幕》

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

关键词:Spring 源码, 依赖注入, DI, IoC 容器, 手写框架, 循环依赖, 构造器注入, 属性注入, Java 反射, BeanReference


本文是手写 Spring 框架系列第二篇,第一篇实现了 IoC 容器的基础功能,本篇实现了 DI 依赖注入功能,敬请期待后续文章…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

加倍巴巴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值