全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-18 12 分钟 ✍️ juanwangdev

Spring 依赖注入原理与循环依赖解决方案

依赖注入是 IoC 的核心实现,循环依赖是 Spring 设计中的重要挑战。

依赖注入方式

三种注入方式对比

方式注解特点推荐场景
构造器注入无/@Autowired(required=false)强依赖、不可变必须依赖
Setter注入@Autowired可选依赖可选依赖
字段注入@Autowired简洁但不推荐不推荐

构造器注入(推荐)

Java
@Service
public class UserService {
    private final UserRepository userRepository;
    private final OrderService orderService;

    // 单构造器无需 @Autowired
    public UserService(UserRepository userRepository, OrderService orderService) {
        this.userRepository = userRepository;
        this.orderService = orderService;
    }
}

Setter 注入

Java
@Service
public class UserService {
    private NotificationService notificationService;

    @Autowired(required = false)  // 可选依赖
    public void setNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }
}

依赖注入源码解析

AutowiredAnnotationBeanPostProcessor

Java
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    // 处理 @Autowired 和 @Value
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        try {
            metadata.inject(bean, beanName, pvs);
        } catch (BeanCreationException ex) {
            throw ex;
        }
        return pvs;
    }
}

注入元数据收集

Java
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
    // 1. 缓存查找
    InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
    if (metadata == null) {
        // 2. 解析类上的 @Autowired 注解
        metadata = buildAutowiringMetadata(clazz);
        this.injectionMetadataCache.put(cacheKey, metadata);
    }
    return metadata;
}

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
    List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();

    // 扫描字段
    ReflectionUtils.doWithLocalFields(clazz, field -> {
        if (field.isAnnotationPresent(Autowired.class)) {
            elements.add(new AutowiredFieldElement(field, true));
        }
    });

    // 扫描方法
    ReflectionUtils.doWithLocalMethods(clazz, method -> {
        if (method.isAnnotationPresent(Autowired.class)) {
            elements.add(new AutowiredMethodElement(method, true, pvs));
        }
    });

    return new InjectionMetadata(clazz, elements);
}

字段注入实现

Java
private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
    private final Field field;
    private final boolean required;

    @Override
    protected void inject(Object bean, String beanName, PropertyValues pvs) {
        // 1. 解析依赖
        Object value = resolveDependency(field.getType(), field.getName(), beanName);

        // 2. 反射设置值
        if (value != null) {
            ReflectionUtils.makeAccessible(field);
            field.set(bean, value);
        } else if (required) {
            throw new BeanCreationException("Required field not found");
        }
    }
}

循环依赖问题

循环依赖类型

类型是否可解决说明
单例 Setter/字段注入✅ 可解决三级缓存
单例 构造器注入❌ 不可解决Lazy 可绕过
Prototype 依赖❌ 不可解决不缓存

循环依赖示例

Java
@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;
}

三级缓存机制

缓存层级

Java
// DefaultSingletonBeanRegistry 核心缓存

// 一级缓存:完整 Bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

// 二级缓存:早期暴露 Bean(已实例化,未初始化)
private final Map<String, Object> earlySingletonObjects = new HashMap(16);

// 三级缓存:ObjectFactory(用于生成早期 Bean)
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

三级缓存流程

Java
1. 创建 ServiceA
   ├─ 实例化 ServiceA(构造函数)
   ├─ 暴露到三级缓存:singletonFactories.put(A, () -> getEarlyBeanReference(A))
   ├─ 属性注入:发现需要 ServiceB
   ↓
2. 创建 ServiceB
   ├─ 实例化 ServiceB
   ├─ 暴露到三级缓存
   ├─ 属性注入:发现需要 ServiceA
   ├─ 从三级缓存获取 ServiceA → 提升到二级缓存
   ├─ ServiceB 完成,放入一级缓存
   ↓
3. ServiceA 属性注入完成
   ├─ ServiceA 完成,放入一级缓存
   ├─ 清理二级、三级缓存

源码实现:getSingleton()

Java
public Object getSingleton(String beanName) {
    // 1. 一级缓存查找
    Object singletonObject = this.singletonObjects.get(beanName);

    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 2. 二级缓存查找
            singletonObject = this.earlySingletonObjects.get(beanName);

            if (singletonObject == null) {
                // 3. 三级缓存查找
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    // 提升到二级缓存
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    // 清理三级缓存
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

暴露早期引用:addSingletonFactory()

Java
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
            // 放入三级缓存
            this.singletonFactories.put(beanName, singletonFactory);
            // 移除二级缓存
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}

AOP 代理处理

Java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;

    // 如果有 SmartInstantiationAwareBeanPostProcessor(如 AOP)
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
            exposedObject = ((SmartInstantiationAwareBeanPostProcessor) bp)
                .getEarlyBeanReference(exposedObject, beanName);
        }
    }
    return exposedObject;
}

构造器循环依赖

问题示例

Java
@Service
public class ServiceA {
    private final ServiceB serviceB;

    public ServiceA(ServiceB serviceB) {
        this.serviceB = serviceB;
    }
}

@Service
public class ServiceB {
    private final ServiceA serviceA;

    public ServiceB(ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

报错:BeanCurrentlyInCreationException - 无法解决构造器循环依赖

解决方案:@Lazy

Java
@Service
public class ServiceA {
    private final ServiceB serviceB;

    public ServiceA(@Lazy ServiceB serviceB) {
        this.serviceB = serviceB;  // 注入代理对象,延迟加载
    }
}

@Service
public class ServiceB {
    private final ServiceA serviceA;

    public ServiceB(@Lazy ServiceA serviceA) {
        this.serviceA = serviceA;
    }
}

@Lazy 原理

Java
// ContextAnnotationAutowireCandidateResolver 解析 @Lazy
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
    if (isLazy(descriptor)) {
        // 创建代理对象,首次使用时才真正获取 Bean
        return buildLazyResolutionProxy(descriptor, beanName);
    }
    return null;
}

Prototype 循环依赖

为什么无法解决

Java
// Prototype Bean 不缓存,每次获取都创建新实例
@Service
@Scope("prototype")
public class PrototypeA {
    @Autowired
    private PrototypeB prototypeB;
}

@Service
@Scope("prototype")
public class PrototypeB {
    @Autowired
    private PrototypeA prototypeA;
}

报错:BeanCurrentlyInCreationException - Prototype Bean 不进入三级缓存

解决方案

Java
@Service
@Scope("prototype")
public class PrototypeA {
    private PrototypeB prototypeB;

    @Autowired
    private ObjectProvider<PrototypeB> prototypeBProvider;

    public void doSomething() {
        // 延迟获取,每次调用获取新实例
        this.prototypeB = prototypeBProvider.getObject();
    }
}

循环依赖调试

查看正在创建的 Bean

YAML
// DefaultSingletonBeanRegistry
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap(16));

public boolean isSingletonCurrentlyInCreation(String beanName) {
    return this.singletonsCurrentlyInCreation.contains(beanName);
}

检查循环依赖配置

text
spring:
  main:
    allow-circular-references: true  # Spring Boot 2.6+ 需显式开启

要点总结

要点说明
三级缓存singletonObjects → earlySingletonObjects → singletonFactories
解决条件单例 + Setter/字段注入
构造器循环不支持,需用 @Lazy
Prototype循环不支持,需用 ObjectProvider
AOP影响三级缓存提前生成代理
二级缓存意义避免重复执行 singletonFactory.getObject()

📝 发现内容有误?点击此处直接编辑

← 上一篇 Spring IoC容器与Bean生命周期源码解析
下一篇 → Spring事件机制原理与实战
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库