Spring循环依赖:三级缓存原理、解决方案与工程实践

Spring循环依赖三级缓存BeanCreationException
于 2026-08-02 03:54:20 修改
·本内容遵循CC 4.0 BY-SA版权协议

最近在开发一个基于 Spring Boot 的微服务项目时,遇到了一个非常典型且令人头疼的问题:服务启动后,部分 Bean 的依赖注入总是失败,控制台反复抛出 NoSuchBeanDefinitionExceptionBeanCreationException。排查过程就像在玩“大家来找茬”,配置文件、注解、包扫描路径查了个遍,最后发现根源竟是一个不起眼的循环依赖问题。这种“你中有我,我中有你”的 Bean 关系,像极了生物学里的“噬菌体”与“宿主菌”——一个必须依赖另一个才能存活和复制,处理不当就会导致整个“生态系统”(应用上下文)崩溃。

本文将深入剖析 Spring 框架中循环依赖这一经典难题。无论你是刚接触 Spring 的新手,还是有一定经验但在复杂项目中踩过坑的开发者,都能通过本文彻底理解循环依赖的产生原理、Spring 的默认解决方案(三级缓存)及其局限性,并掌握一套从编码规范、设计模式到高级特性的完整规避与解决策略。我们将通过可运行的代码示例,一步步复现问题、分析原理并给出最佳实践,让你在未来的项目中能从容应对此类依赖纠缠。

1. 循环依赖:概念、场景与影响

在开始技术拆解之前,我们首先要明确什么是循环依赖,以及它为什么在 Spring 管理的应用中成为一个问题。

1.1 什么是循环依赖?

循环依赖,顾名思义,是指两个或多个 Spring Bean 之间相互持有对方的引用,形成一个闭环。最常见的场景是双向依赖:

  • Bean A 的创建需要注入 Bean B
  • Bean B 的创建又需要注入 Bean A

这就构成了一个简单的循环:A → B → A。

在更复杂的业务系统中,可能会出现更长的依赖链,例如:A → B → C → A,形成一个循环圈。

1.2 为什么这会成为问题?

Spring IoC 容器负责 Bean 的生命周期管理,其核心流程包括:实例化、属性填充、初始化。在遇到循环依赖时,这个流程会陷入一个“先有鸡还是先有蛋”的困境:

  1. 容器开始创建 Bean A,执行实例化(调用构造函数),得到一个“早期对象”。
  2. 接下来要为 Bean A 进行属性填充(依赖注入),发现它依赖 Bean B。
  3. 容器转而开始创建 Bean B,执行实例化,得到 Bean B 的“早期对象”。
  4. 为 Bean B 进行属性填充时,发现它依赖 Bean A。
  5. 此时 Bean A 尚未完成属性填充和初始化,不是一个“完全体”的 Bean。如果容器无法提供这个处于创建中状态的 Bean A 的引用,那么 Bean B 的创建就会失败,进而导致 Bean A 的创建也失败。

1.3 常见产生场景

循环依赖往往隐藏在不当的设计中:

  • 架构设计缺陷:服务层 UserServiceOrderService 相互调用对方的方法,并相互注入。
  • 数据模型关联:实体类 AuthorBook 在业务层被设计成相互依赖的 Bean。
  • 配置类相互引用:两个 @Configuration 类通过 @Bean 方法相互依赖。
  • 过度使用 @Autowired:在字段、构造器、Setter 方法上不加思考地使用自动装配,容易无意中引入循环依赖。

理解问题本质后,我们来看 Spring 是如何尝试解决这个难题的。

2. Spring 的默认解决方案:三级缓存机制

Spring 框架通过其著名的“三级缓存”机制,默认支持解决单例 Bean通过属性注入(Setter 注入)或字段注入方式的循环依赖。这是 Spring 容器的一项高级特性,理解其原理对深入掌握 Spring 至关重要。

2.1 三级缓存定义

DefaultSingletonBeanRegistry 类中,定义了三个关键的 Map,称为三级缓存:

  1. 一级缓存 singletonObjectsConcurrentHashMap<String, Object>。缓存已经完成全部生命周期(实例化、属性填充、初始化)的“成品”单例 Bean。这是我们通常从容器中获取到的 Bean。
  2. 二级缓存 earlySingletonObjectsHashMap<String, Object>。缓存早期的单例对象,这些对象已经实例化,但尚未完成属性填充和初始化。它用于解决循环依赖。
  3. 三级缓存 singletonFactoriesHashMap<String, ObjectFactory<?>>。缓存单例工厂对象。当 Bean 完成实例化后,会将其包装成一个 ObjectFactory 放入此缓存。当发生循环依赖时,会调用这个工厂的 getObject() 方法来获取 Bean 的早期引用(可能会经过 BeanPostProcessor 的处理,如 AOP 代理)。

2.2 解决循环依赖的流程

我们以 BeanABeanB 相互依赖为例,且都采用 @Autowired 字段注入:

  1. 开始创建 BeanA

    • 实例化 BeanA(调用构造函数),得到一个原始对象 aInstance
    • aInstance 包装成一个 ObjectFactory,并放入 三级缓存 (singletonFactories)。
    • 开始属性填充,发现需要注入 BeanB
  2. 转而创建 BeanB

    • 实例化 BeanB,得到 bInstance
    • bInstance 包装成 ObjectFactory,放入三级缓存。
    • 开始属性填充,发现需要注入 BeanA
  3. 解决 BeanBBeanA 的依赖

    • 容器首先从一级缓存找 BeanA,没有。
    • 从二级缓存找,也没有。
    • 从三级缓存找到 BeanAObjectFactory,调用 getObject()。这个方法可能会直接返回 aInstance,也可能通过 AbstractAutoProxyCreator 等后处理器返回一个 AOP 代理对象(这就是为什么 Spring AOP 默认使用 CGLIB 时也能支持循环依赖)。将这个早期引用放入 二级缓存,并从三级缓存移除该工厂。
    • 将获取到的 BeanA 的早期引用注入到 BeanB 中。
    • BeanB 完成属性填充和初始化,成为一个“成品” Bean,被放入 一级缓存,并从二、三级缓存中清理掉 BeanB 的相关条目。
  4. 继续完成 BeanA 的创建

    • 回到 BeanA 的属性填充步骤,现在需要注入 BeanB
    • 此时直接从 一级缓存 中就能获取到“成品” BeanB,将其注入。
    • BeanA 完成属性填充和初始化,成为“成品” Bean,放入 一级缓存,并清理其二、三级缓存条目。

至此,循环依赖被成功解决,两个 Bean 都完成了创建。

2.3 方案的局限性

Spring 的三级缓存机制并非万能,它有以下明确限制:

  • 仅支持单例作用域(Singleton):原型(Prototype)作用域的 Bean 每次都会新建,无法通过缓存解决循环依赖。
  • 依赖注入方式受限
    • 支持:字段注入(@Autowired)、Setter 方法注入。
    • 不支持构造器注入(Constructor Injection)。因为 Bean 实例化的第一步就是调用构造器,如果构造器参数需要另一个 Bean,而另一个 Bean 也需要当前 Bean 作为构造参数,那么双方连第一步(实例化)都无法完成,三级缓存根本无从谈起。Spring 在这种情况下会直接抛出 BeanCurrentlyInCreationException
  • 存在“治标不治本”的风险:三级缓存掩盖了设计上的问题。即使依赖注入成功,Bean 在初始化方法(如 @PostConstruct)中调用对方的方法,可能会因为对方尚未完全初始化而遇到 NullPointerException 或状态不一致的问题。

了解了 Spring 的默认机制和它的边界,我们就可以探讨如何从根本上避免和解决循环依赖。

3. 环境准备与示例项目搭建

为了直观地演示循环依赖的现象和解决方案,我们创建一个简单的 Spring Boot 项目。

3.1 环境与版本说明

  • JDK: 17 或 8
  • Spring Boot: 3.x 或 2.7.x (本文示例基于 3.x,核心原理一致)
  • 构建工具: Maven
  • IDE: IntelliJ IDEA 或 Eclipse

3.2 创建项目与依赖

使用 Spring Initializr 或 IDE 创建项目,主要依赖为 Spring Webpom.xml 关键依赖如下:

XML
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.5</version> <!-- 请使用最新稳定版 -->
<relativePath/>
</parent>
 
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 可选,用于创建Controller测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

3.3 项目结构

创建以下包和类,模拟循环依赖场景:

TEXT
src/main/java/com/example/circulardemo/
├── CircularDemoApplication.java
├── service/
│ ├── ServiceA.java
│ └── ServiceB.java
└── controller/
└── TestController.java (可选,用于触发上下文加载)

4. 循环依赖问题复现与原理分析

4.1 构造器注入导致的循环依赖(Spring 无法解决)

让我们首先创建一个 Spring 无法解决的循环依赖场景。

ServiceA.java

JAVA
package com.example.circulardemo.service;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
@Service
public class ServiceA {
private final ServiceB serviceB;
 
// 构造器注入
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
System.out.println("ServiceA 构造器被调用,依赖ServiceB");
}
 
public String callA() {
return "ServiceA 被调用,准备调用 ServiceB";
}
}

ServiceB.java

JAVA
package com.example.circulardemo.service;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
@Service
public class ServiceB {
private final ServiceA serviceA;
 
// 构造器注入
@Autowired
public ServiceB(ServiceA serviceA) {
this.serviceA = serviceA;
System.out.println("ServiceB 构造器被调用,依赖ServiceA");
}
 
public String callB() {
return "ServiceB 被调用,准备调用 ServiceA";
}
}

启动应用,你会立即看到类似如下的错误,应用启动失败:

TEXT
***************************
APPLICATION FAILED TO START
***************************
 
Description:
 
The dependencies of some of the beans in the application context form a cycle:
 
┌─────┐
| serviceA defined in file [...ServiceA.class]
↑ ↓
| serviceB defined in file [...ServiceB.class]
└─────┘
 
Action:
 
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

错误分析: Spring Boot 2.6+ 版本默认禁用了循环依赖(spring.main.allow-circular-references=false)。即使你在 application.properties 中将其设为 true,对于构造器注入形成的循环依赖,Spring 核心容器依然无法解决,因为 Bean 的实例化步骤都无法完成。错误信息清晰地指出了循环的路径。

4.2 字段/Setter注入导致的循环依赖(Spring 默认可解决)

现在,我们将注入方式改为字段注入,并开启允许循环依赖的配置。

修改 ServiceA 和 ServiceB,使用字段注入:

JAVA
// ServiceA.java
@Service
public class ServiceA {
@Autowired // 字段注入
private ServiceB serviceB;
 
public ServiceA() {
System.out.println("ServiceA 无参构造器被调用");
}
 
public String callA() {
return "ServiceA 被调用,准备调用 ServiceB";
}
}
 
// ServiceB.java
@Service
public class ServiceB {
@Autowired // 字段注入
private ServiceA serviceA;
 
public ServiceB() {
System.out.println("ServiceB 无参构造器被调用");
}
 
public String callB() {
return "ServiceB 被调用,准备调用 ServiceA";
}
}

application.properties 中开启循环依赖支持:

PROPERTIES
# Spring Boot 2.6+
spring.main.allow-circular-references=true

创建一个测试 Controller 来触发 Bean 的加载和使用:

JAVA
package com.example.circulardemo.controller;
 
import com.example.circulardemo.service.ServiceA;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class TestController {
 
@Autowired
private ServiceA serviceA;
 
@GetMapping("/test")
public String test() {
return serviceA.callA();
}
}

启动应用。这次应用可以正常启动,控制台会输出:

TEXT
ServiceA 无参构造器被调用
ServiceB 无参构造器被调用

访问 http://localhost:8080/test,会正常返回响应。这说明 Spring 的三级缓存机制成功解决了字段注入方式的循环依赖。

5. 解决循环依赖的工程化方案

虽然 Spring 能解决部分循环依赖,但依赖这个特性是危险的。我们应该从设计和代码层面主动避免或打破循环。以下是几种工程化的解决方案。

5.1 方案一:代码重构与设计模式

这是最根本、最推荐的解决方案。

1. 提取公共逻辑到第三方面 如果 ServiceAServiceB 相互调用是因为有共同的业务逻辑,可以将这部分逻辑抽取到一个新的 ServiceC(或 CommonService)中,让 AB 都依赖 C,从而将循环依赖变为星型依赖。

TEXT
A → C ← B

2. 使用接口与依赖倒置 定义接口,让依赖关系建立在抽象层上。通过回调、事件或观察者模式解耦。

JAVA
// 1. 定义接口
public interface TaskHandler {
void handle();
}
 
// 2. ServiceA 实现接口,并持有处理器的集合(可能包含ServiceB)
@Service
public class ServiceA implements TaskHandler {
@Autowired
private List<TaskHandler> handlers; // Spring会自动注入所有实现
 
@Override
public void handle() { /* A的逻辑 */ }
public void processAll() {
handlers.forEach(TaskHandler::handle);
}
}
 
// 3. ServiceB 也实现接口,它只依赖接口,不直接依赖ServiceA
@Service
public class ServiceB implements TaskHandler {
@Override
public void handle() { /* B的逻辑 */ }
}

3. 使用方法调用替代属性注入 如果 A 需要 B 的功能仅仅是在某个特定方法中,可以考虑在需要时通过 ApplicationContext 动态获取,或者将 B 作为方法参数传入。但这通常意味着需要调整调用链的设计。

5.2 方案二:使用 @Lazy 注解

@Lazy 注解可以延迟 Bean 的初始化或依赖的注入。将其加在注入点或 Bean 定义上,可以打破循环依赖的初始化顺序。

在注入点使用 @Lazy

JAVA
@Service
public class ServiceA {
private final ServiceB serviceB;
 
@Autowired
public ServiceA(@Lazy ServiceB serviceB) { // 对构造器参数使用@Lazy
this.serviceB = serviceB;
System.out.println("ServiceA 构造器完成,serviceB 是代理对象");
}
}
 
@Service
public class ServiceB {
private final ServiceA serviceA;
 
@Autowired
public ServiceB(@Lazy ServiceA serviceA) { // 对构造器参数使用@Lazy
this.serviceA = serviceA;
System.out.println("ServiceB 构造器完成,serviceA 是代理对象");
}
}

原理@Lazy 会让 Spring 注入一个代理对象,而不是真实的 Bean 实例。当第一次调用代理对象的方法时,才会触发真实 Bean 的初始化。这样,双方构造器都能成功调用,循环依赖被延迟到方法调用时才解决。注意:这并没有消除循环依赖,只是推迟了冲突发生的时间,可能会将启动时错误转化为运行时错误。

5.3 方案三:使用 Setter/字段注入 + @Autowired(配合允许循环引用)

这就是我们前面演示的、Spring 默认支持的方案。它利用三级缓存工作。这是下策,因为它掩盖了设计问题,并且对构造器注入无效。

5.4 方案四:使用 ObjectProviderProvider

Spring 提供了 ObjectProvider(或 JSR-330 的 Provider)接口,用于延迟查找和获取 Bean,它也能用于解决某些循环依赖场景。

JAVA
@Service
public class ServiceA {
private final ObjectProvider<ServiceB> serviceBProvider;
 
@Autowired
public ServiceA(ObjectProvider<ServiceB> serviceBProvider) {
this.serviceBProvider = serviceBProvider;
}
 
public void doSomething() {
ServiceB serviceB = serviceBProvider.getIfAvailable(); // 或 getObject()
// 使用 serviceB
}
}
 
@Service
public class ServiceB {
private final ServiceA serviceA;
 
@Autowired
public ServiceB(ServiceA serviceA) { // B 可以正常注入 A
this.serviceA = serviceA;
}
}

在这个例子中,ServiceA 并不直接依赖 ServiceB 的实例,而是依赖一个能提供 ServiceBObjectProvider。这样 ServiceA 的构造器就能成功执行。当 ServiceA 真正需要 ServiceB 时,再通过 Provider 获取。此时 ServiceB 早已被创建并初始化完成(因为 ServiceB 只依赖已完成的 ServiceA)。

6. 最佳实践与工程建议

  1. 优先使用构造器注入

    • 这是 Spring 官方推荐的方式。它能明确声明 Bean 的强制依赖,保证 Bean 在构造完成后就处于完全初始化的状态(final 字段),并且便于单元测试(无需 Spring 容器即可构造对象)。
    • 构造器注入会强制暴露循环依赖问题,迫使你在设计阶段就解决它,而不是将其隐藏到运行时。
  2. 遵循单一职责与依赖倒置原则

    • 每个类应该有明确且单一的职责。如果两个服务紧密耦合,考虑是否违反了单一职责原则。
    • 依赖于抽象(接口),而非具体实现。使用接口可以更容易地通过设计模式(如策略、观察者)解耦循环依赖。
  3. 谨慎使用 @Lazy

    • @Lazy 作为解决循环依赖的首选方案是危险的。它会使 Bean 的初始化时机变得不确定,可能将启动问题转化为更难调试的运行时问题(如 NullPointerException 在特定业务流中才出现)。
    • @Lazy 更适用于那些初始化成本高、但不一定在应用启动时就需要的 Bean(如连接池、某些客户端)。
  4. 进行架构评审与依赖分析

    • 在项目早期和迭代过程中,定期使用工具(如 IDE 的依赖图、ArchUnit 测试)或通过代码审查来识别潜在的循环依赖。
    • 对于大型项目,考虑将相互依赖紧密的模块合并,或者引入一个新的中间模块来承载共享逻辑。
  5. 理解并接受 Spring 的局限性

    • 明确知道 Spring 只能解决单例、非构造器注入的循环依赖。
    • 对于原型 Bean、@Configuration 类中的 @Bean 方法循环依赖,也需要通过重构或 @Lazy 来解决。
  6. 配置与监控

    • 在生产环境中,保持 spring.main.allow-circular-references=false(Spring Boot 2.6+ 默认值)。这能让循环依赖在启动时快速失败,而不是在运行时引发不可预知的行为。
    • 在测试阶段,可以结合 @SpringBootTest 进行集成测试,确保 Bean 的装配和初始化顺序符合预期。

7. 常见问题排查清单

当遇到 BeanCurrentlyInCreationException 或与循环依赖相关的诡异行为时,可以按照以下步骤排查:

问题现象 可能原因 排查步骤与解决方案
应用启动失败,报 BeanCurrentlyInCreationException,并显示循环链。 1. 构造器注入导致的循环依赖。
2. 原型(Prototype) Bean的循环依赖。
3. @Configuration 类中 @Bean 方法相互调用。
1. 分析错误日志:Spring 给出的循环链非常清晰,直接定位到涉及的 Bean。
2. 检查注入方式:将构造器注入改为 Setter/字段注入不是好办法,应优先考虑重构设计,提取公共逻辑或引入接口。
3. 检查 Bean 作用域:确认是否为 @Scope(“prototype”),考虑是否真的需要原型模式。
应用能启动,但在调用某个特定方法时抛出 NullPointerExceptionLazyInitializationException 1. 使用了 @Lazy,但代理对象在错误的时间点被访问。
2. 在 @PostConstruct 方法中调用了循环依赖对方的方法,而对方可能还未完成初始化。
1. 检查 @Lazy 的使用:确保在调用 @Lazy Bean 的方法时,其依赖项已准备就绪。
2. 避免在生命周期回调中使用循环依赖:不要在 @PostConstructInitializingBean.afterPropertiesSet() 或构造器中调用可能尚未完全初始化的依赖 Bean 的业务方法。
字段注入的循环依赖,在 Spring Boot 2.6+ 下启动失败。 Spring Boot 2.6 开始默认禁止循环引用。 1. 首选方案重构代码,打破循环。
2. 临时方案:在 application.properties 中设置 spring.main.allow-circular-references=true务必清楚这只是临时绕过,并评估风险。
使用 @Async@Transactional 等 AOP 代理时,循环依赖出现问题。 AOP 代理可能干扰了三级缓存的正常工作流程,尤其是在使用 JDK 动态代理且代理基于接口时。 1. 确保 AOP 代理模式一致:默认使用 CGLIB 代理 (spring.aop.proxy-target-class=true) 对循环依赖支持更好。
2. 尝试对循环依赖的一方使用 @Lazy
3. 考虑将 AOP 切面逻辑移到循环依赖链之外的服务中。

循环依赖是 Spring 开发中的一个深水区问题,它既是技术挑战,也是软件设计质量的试金石。Spring 提供的三级缓存机制是一个精巧的工程解决方案,但它更像是一把“安全锤”,用于在紧急情况下破窗,而不应作为架构设计的常规工具。优秀的系统设计应当追求清晰、单向的依赖关系。当循环依赖出现时,把它视为一个重构代码、优化架构的宝贵信号。通过本次对“噬菌体”式循环依赖的全面剖析,希望你能掌握其原理、解决方案与避坑指南,从而构建出更加健壮、可维护的 Spring 应用。

Spring知识梳理(3)
本文系统梳理Spring中三种依赖注入方式(构造器、Setter、字段注入)的原理、优劣及官方推荐依据,并深入剖析循环依赖问题定义、Spring三级缓存解决方案、为何需三级而非两级(核心在于AOP代理时机)、构造器注入无法解决的原因,以及实际开发中的重构建议。内容聚焦面试高频考点与工程实践要点。
蓝胖的四次元口袋
388
Java面试核心技巧JVM、HashMap与Spring深度解析
本文聚焦Java技术面试三大核心JVM内存模型GC机制(含TLAB、GC Roots、Metaspace)、HashMap底层原理(扩容机制、红黑树阈值、线程安全问题)及Spring三级缓存与循环依赖解决方案。涵盖高频真题解析、白板编码技巧、设计模式类比表达,并强调源码理解、调试工具(Arthas、MAT、jstack)和工程实践能力(布隆过滤器、Jacoco、Conditional注解)等关键考察维度。
张云雷宝宝
212
Spring 循环依赖三级缓存
深入剖析Spring框架中循环依赖的处理机制及其三级缓存的运作原理,揭示如何通过不同缓存层级解决循环依赖问题,同时保持AOP代理的正确性。
程序源程序
61724
Spring 循环依赖解决方案
本文详细探讨了Spring中的循环依赖问题,包括构造器和字段注入的差异,以及Spring如何通过三级缓存机制解决循环依赖Spring在初始化Bean时,如果遇到循环依赖,会利用三级缓存中的对象工厂实例提前生成Bean,以解决单例模式下的循环依赖。同时,介绍了@Lazy注解用于延迟加载,以及setter注入作为解决方案。此外,文章还解释了为何需要三级缓存,以及构造器注入导致循环依赖的原因和解决方案
daiwei-dave
20972
Spring 解决循环依赖为什么需要三级缓存,而不是两级缓存?
本文探讨了Spring框架如何通过三级缓存机制解决循环依赖问题,解释了三级缓存的必要性,以及在Bean实例化过程中的工作原理,强调了其在依赖注入和代理处理上的优势。,
有来技术
8136
Spring三级缓存解决循环依赖
深入剖析Spring框架中循环依赖的处理机制,包括构造器注入、singleton和prototype模式下的循环依赖场景,以及Spring解决循环依赖原理
fedorafrog
25386
深度解析 Spring 源码:三级缓存机制探究
本文详细介绍了Spring中的三级缓存系统,包括其概述、实现原理、使用场景和注意事项,重点讨论了它如何提高性能、解决循环依赖和懒加载,以及可能遇到的问题和解决方法。
忆愿
8128
Spring循环依赖三级缓存是否可以减少为二级缓存
深入探讨Spring框架如何利用三级缓存机制解决循环依赖问题,分析二级缓存替代方案及其对Spring设计原则的影响。
自由的♂
3824
深入解析Spring框架底层原理:循环依赖三级缓存与AOP代理冲突
本文深入探讨了Spring框架中循环依赖问题及其AOP代理的冲突。通过三级缓存机制,Spring有效解决了Bean之间的相互依赖问题,并利用ObjectFactory实现了动态代理的兼容处理。文章详细分析了循环依赖的典型场景、三级缓存的工作原理AOP的协同机制,揭示了Spring在设计上的智慧。
码字的字节
2155
《深入理解Spring原理》 04-Spring利用 “三级缓存” 解决循环依赖
本文深入分析Spring框架中Bean的循环依赖问题,详细解释了构造器注入Field属性注入两种方式下循环依赖的表现解决策略,重点阐述了Spring的“三级缓存”机制如何巧妙解决循环依赖,提供了一个清晰的循环依赖解决流程。
jackcheng1117
9553
Spring 三级缓存解决循环依赖原理分析
本文详细解读Spring容器的三级缓存结构,包括其产生原因、如何解决循环依赖导致的死循环和AOP代理问题,以及工厂池在创建流程中的关键作用。
Marvin-Fox
4229
【史上最详细,没有之一】Spring三级缓存】解决【循环依赖】的流程梳理,原理和核心代码分析
本文详细阐述了Spring框架中如何利用三级缓存解决循环依赖问题,包括半成品Bean的概念、循环依赖产生的原因及解决流程,同时对比了有无AOP情况下的处理差异。
passerbyYSQ
8990
Spring 循环依赖详解问题分析与三级缓存解决方案
本文聚焦Spring框架中的循环依赖问题,介绍了构造器注入、Setter注入等解决循环依赖的方法,阐述了Spring使用三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)处理循环依赖原理,还解释了为何使用三级缓存而非二级缓存,保证了依赖处理的灵活性和可靠性。
南 阳
1877
Spring系列五:Spring怎么解决循环依赖
本文详细介绍了Spring循环依赖的概念及其解决方案,特别是针对单例Bean的三级缓存处理机制。同时,解释了为什么Spring不支持基于构造器注入的循环依赖,并阐述了setter注入循环依赖的解决过程。此外,还剖析了@Autowired注解的实现原理,涉及BeanPostProcessor和后置处理器在属性填充中的作用。
叶秋学长
10225
Spring 循环依赖的源码深度探究以及三级缓存原理【一万字】
本文深入探讨了Spring框架如何处理循环依赖,特别是针对setter注入和字段注解反射注入的单例bean。Spring通过三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)来解决这类循环依赖。在创建bean实例时,如果发现循环依赖,会先创建一个早期的bean实例放入缓存,然后在后续装配中完成依赖注入。对于AOP代理,Spring能够处理基于AbstractAutoProxyCreator的代理对象间的循环依赖,但对于其他方式创建的代理,如Spring异步任务,需要通过@Lazy解决。此外,Spring不支持构造器注入的循环依赖,但可以通过@Lazy解决。文章还详细分析了循环依赖的处理流程,并总结了Spring可以和不能解决的循环依赖场景。
刘Java
4064
Spring三级缓存解决循环依赖问题详解
本文深入探讨Spring框架如何解决单例Bean的setter注入循环依赖问题,分析循环依赖的种类及解决原理,详细介绍Bean的生命周期,解释为何需要使用三级缓存
花语。
4624
Spring循环依赖与三级缓存
本文详细介绍了Spring如何处理循环依赖,通过三级缓存(singletonObjects, earlySingletonObjects, singletonFactories)来实现。在创建Bean的过程中,分别尝试从一级、二级、三级缓存获取Bean,防止重复创建。在多线程环境下,三级缓存对于确保正确创建Bean至关重要。 127549793,12186678,日志记录监控安全CRLF注入审计漏洞,['安全', 'web安全', '安全威胁分析']
Only_周
5036
Spring使用三级缓存解决循环依赖的源码分析。
本文基于Spring 5.x版本,解析Spring三级缓存解决循环依赖的源码。介绍了三级缓存定义,阐述解决循环依赖的源码流程,分析关键源码方法,解释为何需三级缓存,指出循环依赖的限制,如构造函数注入和原型作用域Bean不支持,还可用流程图辅助理解。
一个儒雅随和的男子
1685
深度解析Spring核心原理:循环依赖的“三级缓存”机制
本文深入剖析Spring循环依赖问题,阐述其典型场景、根源、危害及解决必要性。重点解析三级缓存机制,包括结构、工作流程、协同示例等,还探讨单例模式应用、构造器循环依赖无法解决的原因,最后提供面试常见问题解析,展现Spring设计的智慧前瞻性。
码字的字节
1836
三级缓存---解决 Spring 循环依赖
本文深入探讨Spring框架如何解决循环依赖问题,介绍了循环依赖的三种类型及解决方案,详细解析了Spring三级缓存机制,包括earlySingletonObjects、singletonObjects和singletonFactories的作用及工作原理
二价亚铁.
2040
spring依赖注入的实现原理
Spring依赖注入(Dependency Injection,简称DI)是Spring框架最核心的特性之一,其本质是实现控制反转(Inversion of Control,IoC)的具体手段。依赖注入并非Spring独创的概念,而是面向对象设计中解耦组件间依赖关系的一种通用范式;但Spring通过高度抽象、可扩展且生产就绪的IoC容器,将DI提升为一套成熟、健壮、可配置、可扩展的企业级基础设施。其底层实现原理横跨Java反射机制、元数据解析、生命周期管理、代理增强、并发控制与循环依赖破除等多个关键技术领域,构成一个精密协同的运行时系统。首先,Spring的IoC容器以BeanFactory为最顶层接口,定义了获取Bean、类型检查、作用域管理等基础能力;而ApplicationContext则是其功能完备的子接口,不仅继承BeanFactory全部能力,还额外集成AOP代理支持、国际化(i18n)、事件发布(ApplicationEvent)、资源加载(ResourceLoader)、环境抽象(Environment)及注解驱动(如@Component、@Service)等高级特性。容器启动时,并非立即实例化所有Bean,而是先解析配置元数据——无论是XML中的标签、Java Config中的@Bean方法,还是类路径扫描到的@Component注解类——最终统一转化为BeanDefinition对象。BeanDefinition是Spring对Bean“蓝图”的抽象封装,包含类名、作用域(singleton/prototype)、是否懒加载、初始化/销毁方法名、构造参数、属性值、依赖引用(depends-on)、自动装配模式(byType/byName/constructor)以及大量扩展点钩子(如factory-bean、factory-method),是整个依赖注入流程的元数据基石。依赖注入的核心执行阶段发生在Bean实例化属性填充环节。Spring采用三级缓存策略(singletonObjects、earlySingletonObjects、singletonFactories)巧妙解决单例Bean间的循环依赖问题当A依赖B、B又依赖A时,Spring在A完成构造器调用后、尚未设置属性前,将其原始引用(可能为未完全初始化的ObjectFactory)提前暴露至三级缓存;当B创建过程中需要注入A时,从三级缓存中获取该工厂并调用getObject()生成早期引用,从而打破死锁。此机制仅对singleton作用域+setter注入有效,不适用于prototype或构造器注入场景,也凸显了Spring工程实践与理论严谨性之间的务实权衡。@Autowired注解的解析则依托于AutowiredAnnotationBeanPostProcessor这一后置处理器(BeanPostProcessor)。它在Bean实例化后、初始化前(postProcessProperties阶段)介入,遍历目标Bean的所有字段、方法和构造器,识别@Autowired、@Value、@Inject等注解,结合BeanFactory的getBeanNamesForType()等API进行类型匹配(Type Matching),再依据@Qualifier限定符或字段名进一步缩小候选Bean范围,最终通过反射调用set方法或Field.set()完成注入。值得注意的是,@Autowired默认要求依赖必须存在,可通过required=false放宽约束;而@Primary@Profile则分别用于多实现类场景下的优先级控制环境条件筛选,体现了Spring强大的上下文感知能力。此外,Bean的完整生命周期由InstantiationAwareBeanPostProcessor、InitializingBean、DisposableBean、@PostConstruct/@PreDestroy及自定义init-method/destroy-method共同编织。例如,CommonAnnotationBeanPostProcessor负责处理JSR-250规范注解,而ApplicationContextAwareProcessor则确保Bean能感知容器本身。所有这些扩展点均基于SPI思想设计,允许开发者通过注册自定义后置处理器深度定制Bean创建逻辑——如MyBatis的SqlSessionFactoryBean即通过FactoryBean接口将复杂资源封装为普通Bean,再经由getObject()返回代理对象,完美融入Spring生命周期。综上所述,Spring依赖注入绝非简单的“赋值操作”,而是一套融合元数据建模(BeanDefinition)、动态字节码操作(CGLIB/JDK Proxy)、反射调用(Field/Method/Constructor)、缓存一致性协议(三级缓存)、事件驱动模型(ApplicationEvent)、并发安全控制(ConcurrentHashMap + synchronized块)开放式扩展架构(BeanPostProcessor/BeanFactoryPostProcessor)的综合性解决方案。它将软件设计原则(如依赖倒置、单一职责、开闭原则)转化为可落地的编程模型,使业务代码彻底摆脱new关键字硬编码依赖,转向声明式、可测试、可监控、可热替换的现代应用架构范式。理解其原理,不仅是掌握Spring的关键,更是深入理解JVM运行机制、Java语言特性和企业级系统设计哲学的重要入口。
weixin_38669628
Spring面试题概述[项目代码]
Spring框架作为Java企业级开发的基石,其设计理念、核心机制与工程实践构成了Java后端工程师技术能力的重要衡量维度,尤其在中高级岗位面试中,Spring相关问题几乎必考且深度显著。所谓“Spring面试题概述”,绝非简单罗列问答清单,而是对整个Spring生态体系的知识图谱进行系统性解构与原理级还原。首先,Spring最根本的定位是轻量级、非侵入式的开源Java框架,它通过高度模块化设计(Core Container、AOP、Data Access/Integration、Web、Test等)解耦企业应用各层职责,支撑从单体架构到微服务演进的全生命周期开发。其中,IOC(Inversion of Control,控制反转)并非Spring独创概念,但Spring将其工程化推向极致——容器(ApplicationContext)作为核心运行时环境,接管对象的创建、装配、依赖解析生命周期管理,开发者不再通过new关键字硬编码实例化逻辑,而是将控制权“反转”给框架,从而实现松耦合、高内聚、易测试、可配置的架构目标。依赖注入(DI)作为IOC的具体实现方式,涵盖构造器注入(推荐,保证不可变性强制依赖)、Setter注入(灵活性高,支持循环依赖部分场景)和字段注入(@Autowired,便捷但破坏封装性、不利于单元测试),三者在Spring 4.3+后对构造器注入给予优先支持,体现框架对不可变对象线程安全的底层重视。Bean作为Spring管理的基本单元,其作用域(Scope)直接决定对象复用策略内存模型singleton(默认,全局唯一,需注意线程安全)、prototype(每次请求新建实例)、request/session/application(Web环境特有,绑定HTTP生命周期)、websocket(长连接场景)。而Bean生命周期则是一条精密编排的执行链路从Resource加载配置→BeanDefinition解析→实例化(反射或CGLIB)→属性填充(DI注入)→Aware接口回调(如BeanFactoryAware、ApplicationContextAware)→BeanPostProcessor前置处理→InitializingBean.afterPropertiesSet()→自定义init-method→BeanPostProcessor后置处理→就绪使用→容器关闭前执行DisposableBean.destroy()或destroy-method。这一链条中,BeanPostProcessor是AOP代理生成、@Value注入、@PostConstruct/@PreDestroy等注解生效的关键钩子,也是理解Spring扩展机制的核心入口。Spring事务管理是另一高频深水区。声明式事务(@Transactional)基于AOP动态代理实现,底层依赖TransactionManager(如DataSourceTransactionManager)PlatformTransactionManager统一抽象,其隔离级别(ISOLATION_DEFAULT/READ_UNCOMMITTED/READ_COMMITTED/REPEATABLE_READ/SERIALIZABLE)解决脏读、不可重复读、幻读问题;传播行为(REQUIRED/REQUIRES_NEW/SUPPORTS/NOT_SUPPORTED/NEVER/NESTED)则精细控制嵌套调用中事务边界的开启、挂起、嵌套独立性,例如REQUIRED是默认值,若当前存在事务则加入,否则新建;REQUIRES_NEW则强制挂起当前事务并启动全新事务,适用于日志记录等强独立性场景。编程式事务(TransactionTemplate)虽灵活但侵入性强,已逐渐被声明式取代。此外,@Autowired@Resource本质差异在于来源标准前者为Spring原生注解,按类型(Type)匹配,配合@Qualifier指定名称;后者为JSR-250标准注解,优先按名称(Name)匹配,未指定name时才回退至类型匹配,二者在多实现类注入场景下行为迥异。循环依赖解决方案则暴露Spring三级缓存机制(SingletonObjects一级缓存、EarlySingletonObjects二级缓存、SingletonFactories三级缓存工厂)提前曝光(early reference)策略,仅支持单例Bean的setter注入循环依赖,构造器注入因实例化顺序刚性无法解环,需重构设计。AOP通知类型(Before/After/AfterReturning/AfterThrowing/Around)构成横切逻辑织入的完整语义,其中Around最为强大,可控制目标方法是否执行、修改参数返回值、捕获异常,是性能监控、权限校验、分布式锁等场景的底层支撑。所有这些知识点并非孤立存在,而是彼此咬合IOC容器是AOP代理的宿主,事务代理是AOP的一种具体实现,Bean生命周期钩子是自定义增强的入口,模块化设计让数据访问层(JDBC/ORM)Web层(MVC/WebFlux)得以无缝集成。深入掌握这些机制,不仅应对面试游刃有余,更是构建高性能、高可用、可维护Java系统的根本保障。
人间计算器
Spring 学习笔记四
Spring 学习笔记四作为系列化学习文档的重要一环,系统性地深化了对Spring框架核心机制高级特性的理解,其内容虽未在描述中直接展开,但结合标题、标签及压缩包内唯一子文件名“Spring”可高度推断该笔记聚焦于Spring框架的进阶架构原理与工程实践整合能力,尤其强调IoC(Inversion of Control,控制反转)容器的底层实现逻辑、AOP(Aspect-Oriented Programming,面向切面编程)的动态代理机制、Bean生命周期各阶段的钩子方法调用顺序自定义扩展点、依赖注入(Dependency Injection)的多种方式(构造器注入、Setter注入、字段注入、接口注入)及其在循环依赖场景下的解决方案;同时涵盖Spring MVC的请求处理全流程——从DispatcherServlet前端控制器的初始化、HandlerMapping定位处理器、HandlerAdapter适配执行、ModelAndView视图解析到View渲染输出;事务管理部分深入剖析了基于@Transactional声明式事务的传播行为(如REQUIRED、REQUIRES_NEW、NESTED等)、隔离级别(READ_UNCOMMITTED至SERIALIZABLE)、超时设置、只读优化及回滚规则,并揭示其背后基于AOP+TransactionInterceptor+PlatformTransactionManager的代理织入机制;值得注意的是,该笔记还前瞻性地引入Spring Boot的自动配置原理(@EnableAutoConfiguration触发条件化装配、spring.factories机制、AutoConfigurationImportSelector类加载流程)、起步依赖(Starter)的设计哲学以及外部化配置(application.properties/yml)Profile多环境支持策略。在技术深度上,它必然涉及BeanFactoryApplicationContext的继承体系差异(后者提供AOP、事件发布、国际化、资源访问等企业级能力),DefaultListableBeanFactory作为核心注册中心如何维护BeanDefinition元数据、SingletonObjects一级缓存与earlySingletonObjects三级缓存协同解决循环依赖问题;AOP部分必详述JDK动态代理(基于接口)CGLIB代理(基于子类)的适用边界、ProxyFactoryBeanAspectJAutoProxyCreator的配置差异、Pointcut表达式语法(execution、within、this、target、args等)及通知类型(@Before、@After、@Around、@AfterReturning、@AfterThrowing)的执行时机异常处理语义;Bean生命周期则覆盖实例化(Instantiation)、属性填充(Populate)、Aware接口回调(BeanNameAware、BeanFactoryAware、ApplicationContextAware)、BeanPostProcessor前置/后置处理、InitializingBean.afterPropertiesSet()、自定义init-method、DisposableBean.destroy()、自定义destroy-method等12个以上关键节点,并解释为何@PostConstruct和@PreDestroy需配合CommonAnnotationBeanPostProcessor生效;此外,事务管理必然对比编程式事务(TransactionTemplate)声明式事务的适用场景,并分析事务失效的典型原因(如this调用、非public方法、异常未抛出、代理对象获取错误等)。整体而言,“Spring 学习笔记四”并非孤立知识点罗列,而是以“容器即基石、代理为纽带、生命周期为脉络、事务为保障、MVC为入口、Boot为演进”的立体视角,构建起覆盖Spring 4.x至5.x主流版本的完整知识图谱,为开发者从API使用者跃升为框架理解者定制者奠定坚实基础,是掌握企业级Java应用开发底层逻辑不可或缺的关键文献。
weixin_38669628
深入学习Spring
《深入学习Spring》作为一本面向Java高级开发者的系统性技术专著,其核心价值不仅在于对Spring框架使用层面的全面覆盖,更在于以源码为镜、以设计为纲、以工程实践为基,构建起一套完整的Spring认知体系。该书从最基础的IoC(Inversion of Control,控制反转)容器原理出发,深入剖析Spring如何通过BeanFactoryApplicationContext两大核心接口抽象出统一的容器模型,并在此基础上实现高度可扩展的组件管理机制。书中详细拆解了Spring IoC容器的启动流程从Resource定位、BeanDefinition加载注册、依赖解析、Bean实例化(含构造器注入工厂方法)、属性填充(Setter注入)、Aware接口回调(如BeanNameAware、BeanFactoryAware)、InitializingBeaninit-method初始化钩子,到DisposableBeandestroy-method销毁逻辑——完整呈现Bean生命周期的11个关键阶段,每一步均对应Spring源码中AbstractBeanFactory、AbstractAutowireCapableBeanFactory、DefaultListableBeanFactory等核心类的具体实现逻辑。在依赖注入(Dependency Injection)维度,本书超越了XML配置@Component注解的表层用法,深入探讨了@Autowired、@Resource、@Inject三种注入方式的解析优先级、类型匹配策略(Primary、Qualifier)、循环依赖解决方案三级缓存机制singletonObjects、earlySingletonObjects、singletonFactories),并结合源码揭示Spring为何能通过提前暴露ObjectFactory解决setter注入的循环依赖,却无法处理构造器注入的循环依赖这一本质限制。尤为珍贵的是,书中对Spring AOP(Aspect-Oriented Programming)的剖析直击底层从Advisor、Advice、Pointcut、JoinPoint四大核心概念建模,到ProxyFactoryBeanAbstractAutoProxyCreator的代理创建机制;从JDK动态代理(基于接口)CGLIB代理(基于子类)的触发条件性能权衡,到@EnableAspectJAutoProxy注解背后的ImportBeanDefinitionRegistrar扩展点注册、AspectJAutoProxyRegistrar自动代理后处理器注入、以及AnnotationAwareAspectJAutoProxyCreator对切面Bean的识别增强织入全过程。代理模式在此处不再是一个孤立的设计模式案例,而是被升华为Spring实现横切关注点解耦的基础设施语言。设计模式的贯穿式讲解是本书区别于普通教程的关键特质。全书将23种GoF经典模式自然融入Spring架构肌理单例模式支撑Bean默认作用域实现;工厂模式体现于BeanFactory体系AbstractBeanFactory.createBean()方法族;模板方法模式驱动JdbcTemplate、RestTemplate等模板类的统一执行流程;观察者模式用于ApplicationEventPublisher事件发布/监听机制;装饰器模式体现在各种Wrapper类(如RequestWrapper、ResponseWrapper)对HTTP请求响应的增强;责任链模式则隐含于FilterChain、HandlerExecutionChain等Web层处理链结构中。尤其对代理模式的深度演绎,不仅涵盖静态代理动态代理的技术实现差异,更延伸至Spring Security中MethodSecurityInterceptor对方法调用的拦截增强、Spring Transaction中TransactionInterceptor对事务边界的控制,使读者真正理解“模式即思想,框架即实践”。针对Spring Boot,本书并未止步于@SpringBootApplication的自动装配黑盒,而是逐层揭开spring-boot-autoconfigure模块的运作机理从META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(原spring.factories)文件的加载,到AutoConfigurationImportSelector利用SpringFactoriesLoader读取所有自动配置类,再到ConditionEvaluator基于@Conditional系列注解(@ConditionalOnClass、@ConditionalOnMissingBean等)完成精准装配决策。同时结合Spring Boot 3.x对Jakarta EE命名空间的迁移、GraalVM原生镜像支持、Observability可观测性增强等前沿特性,构建起面向云原生时代的Spring技术演进图谱。而压缩包中《精通Spring(清晰书签版)》的双分卷结构,恰恰印证了该书内容体量之庞大、知识密度之高——part1聚焦核心容器AOP原理,part2则纵深拓展至数据访问(JDBC/ORM集成)、Web MVC/WebFlux响应式编程、消息驱动(Spring Messaging/Kafka/RabbitMQ)、测试(Spring TestContext Framework)、安全(Spring Security核心过滤器链)、以及微服务生态(Spring Cloud Alibaba/Nacos/Sentinel)等企业级应用全栈能力。这种由内而外、由点及面、由理论到源码、由模式到架构的知识组织逻辑,使其成为Java工程师突破技术瓶颈、构建系统性思维、迈向架构师层级不可替代的里程碑式读物。
Spring高频题整理[源码]
Spring框架作为Java企业级开发的基石,其设计理念、核心机制与工程实践深度影响着现代微服务架构云原生应用的构建方式。所谓“Spring高频题整理[源码]”,绝非简单罗列面试问答,而是一套系统化、结构化、源码级纵深的知识图谱,覆盖从初学者认知边界到资深架构师决策依据的完整能力光谱。首先,Spring的核心思想——控制反转(IoC)面向切面编程(AOP)并非孤立概念,而是彼此支撑的双螺旋结构IoC解决对象创建依赖关系解耦问题,将传统硬编码的new操作交由容器统一管理,实现“对象的定义权”“使用权”的分离;而AOP则在此基础上进一步抽象横切关注点(如日志、事务、安全、监控),通过动态代理(JDK Proxy或CGLIB)、织入(Weaving)切点表达式(Pointcut Expression)等机制,在不侵入业务逻辑的前提下实现行为增强。这种分层抽象能力,正是Spring能成为事实标准的关键。在IoC容器层面,BeanFactoryApplicationContext的差异远不止于“功能多寡”。BeanFactory是Spring最底层的IoC容器接口,提供基本的Bean实例化、依赖注入生命周期管理能力,但不具备国际化、事件发布、AOP集成等高级特性;而ApplicationContext继承自BeanFactory,是面向企业级应用的“全功能容器”,其典型实现类如ClassPathXmlApplicationContext、AnnotationConfigApplicationContext、GenericApplicationContext等,不仅支持XML、Java Config、Groovy等多种配置方式,更内置了Environment抽象、ResourceLoader、ApplicationEventPublisher等扩展点,为Spring Boot自动配置(Auto-Configuration)条件化装配(@Conditional)奠定基础。尤其值得注意的是,ApplicationContext在启动阶段即完成所有单例Bean的预实例化(除非设置lazy-init),并通过BeanPostProcessor(如AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor)对Bean进行后置处理,这是理解@Autowired、@Value、@PostConstruct等注解生效原理的源码入口。关于依赖注入(DI),Spring支持构造器注入(Constructor Injection)、设值注入(Setter Injection)和接口注入(Interface Injection,已基本弃用)三种方式。其中,构造器注入因其不可变性、强制依赖显式化、天然支持final字段等优势,被Spring官方强烈推荐(尤其在Spring 5+及Spring Boot 2.0+中),它直接对应BeanDefinition中constructorArgumentValues的解析反射调用逻辑;而设值注入虽灵活性高,却易导致对象处于半初始化状态,需配合@Required或@PostConstruct保障完整性。更深层地,依赖注入的本质是Spring容器对BeanDefinitionRegistry中注册的BeanDefinition进行实例化、属性填充、初始化及后置处理的完整闭环,涉及InstantiationStrategy(SimpleInstantiationStrategy/CglibSubclassingInstantiationStrategy)、BeanWrapperImpl、TypeConverter等核心组件,这些均在org.springframework.beans包下有清晰源码实现。Spring Bean的作用域(Scope)体系同样极具设计深度singleton(默认,容器内唯一实例,但非线程安全)、prototype(每次请求新建实例)、request/session/application(Web环境专属)、websocket(Spring 4.1新增)等,其背后由Scope接口及RequestScope、SessionScope等具体实现支撑,配合ThreadLocal存储当前请求上下文,体现Spring对不同运行环境的精细适配能力。Bean生命周期则贯穿实例化(Instantiation)、属性赋值(Populate Properties)、初始化(InitializingBean#afterPropertiesSet / @PostConstruct / init-method)、可用(Ready for Use)、销毁(DisposableBean#destroy / @PreDestroy / destroy-method)全过程,每个阶段均可通过Aware接口(如BeanFactoryAware、ApplicationContextAware)、BeanPostProcessor、InitializingBean、DisposableBean等扩展点介入,构成高度可插拔的生命周期钩子体系。事务管理方面,Spring并未替代数据库事务,而是以声明式事务(@Transactional)为核心,通过TransactionInterceptor拦截方法调用,委托PlatformTransactionManager(如DataSourceTransactionManager、JtaTransactionManager)执行doBegin/doCommit/doRollback,并利用ThreadLocal绑定TransactionStatus实现事务传播行为(PROPAGATION_REQUIRED/REQUIRES_NEW等)。其本质是AOP事务API的深度整合,源码中TransactionAspectSupport类封装了完整的事务切面逻辑,而@Transactional的rollbackFor/noRollbackFor、timeout、isolation等属性,最终都转化为DefaultTransactionDefinition的配置参数,经由TransactionManager解析执行。循环依赖问题的解决方案更是Spring源码的经典范例:三级缓存(singletonObjects、earlySingletonObjects、singletonFactories)机制精准破解了单例Bean间的构造器循环依赖(无法解决)设值循环依赖(可解决)难题。当A依赖B、B又依赖A时,Spring在A实例化后但未初始化前,将其ObjectFactory提前暴露至三级缓存,待B需要A时,通过ObjectFactory#getObject()获取早期引用并放入二级缓存,从而打破死锁。这一设计充分体现了Spring对Java对象生命周期JVM内存模型的深刻把握。此外,Spring 5.0引入的函数式Web框架(WebFlux)、响应式编程支持(Reactor集成)、Kotlin语言一级支持、以及Spring Native(基于GraalVM的AOT编译)等新特性,标志着Spring正从传统Servlet容器向云原生、Serverless、低延迟场景持续演进。源码中spring-context、spring-aop、spring-tx、spring-webflux等模块的包结构、类继承体系接口契约,本身就是一套高质量的软件工程范本。掌握这85道高频题,本质上是在源码层级重构Spring的设计哲学——松耦合、高内聚、可扩展、可测试。唯有穿透注解表象,直抵AbstractBeanFactory#doGetBean、AbstractAutowireCapableBeanFactory#initializeBean、TransactionAspectSupport#invokeWithinTransaction等核心方法,方能在分布式系统复杂度指数级增长的今天,真正驾驭Spring这一企业级开发的“操作系统”。
spring_day02_spring_
Spring框架的IoC(Inversion of Control,控制反转)容器是其最核心、最基础的架构设计思想实现机制,而Spring Day02的学习内容正是围绕IoC容器的多种实现方式及其演进路径展开的深度实践。标题“spring_day02_spring_”虽简略,实则精准指向Spring第二日教学的核心脉络从XML配置驱动的原始IoC容器起步,逐步过渡到纯注解驱动(Annotation-based IoC)、混合配置(@Configuration + @Bean),最终迈向零XML的全注解开发范式。描述中“heima spring source code day 02”进一步明确了这是黑马程序员Spring源码解析系列课程的第二天内容,强调不仅停留在API使用层面,更注重底层原理剖析源码级理解——例如BeanFactoryApplicationContext的继承关系、BeanDefinition的注册流程、BeanPostProcessor的执行时机、依赖注入(DI)的三级缓存机制等关键内核。从【标签】可见,本日知识体系横跨传统现代两大Spring配置范式一方面涵盖经典的XML配置(标签、ref/property注入、scope属性、init-method/destroy-method生命周期钩子),另一方面全面覆盖主流注解体系——@Component及其派生注解(@Service/@Repository/@Controller)、@Configuration声明配置类、@Bean定义工厂方法、@Autowired/@Resource/@Qualifier实现依赖注入、@Scope控制作用域、@Lazy延迟加载、@Primary解决多Bean冲突等。尤为关键的是,@Configuration类并非简单替代XML,其背后依托CGLIB动态代理实现@Bean方法的单例复用(避免重复创建),这普通@Component类存在本质差异,涉及Spring对@Configuration类的特殊增强逻辑(Enhanced Configuration),是理解Spring启动时BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor协同工作的前提。压缩包中四个子项目名称揭示了清晰的技术演进路线图day02_eesy_01anno_ioc是纯注解起步(仅用@Component+@Autowired,无XML,但依赖@ComponentScan扫描);day02_eesy_02account_xmlioc回归XML根基,展示基于ClassPathXmlApplicationContext加载beans.xml的传统方式,包含id/ref、构造器注入、setter注入、集合类型注入(list/map/set/props)等完整语法;day02_eesy_03account_annoioc引入@Import、@Conditional等高级注解,实现条件化Bean注册模块化配置;而day02_eesy_04account_annoioc_withoutxml则是终极形态——彻底摒弃XML,采用JavaConfig(@Configuration + @Bean)配合@EnableXXX系列注解(如@EnableAspectJAutoProxy)构建可编程、可继承、可测试的配置体系。此路径深刻体现了Spring从“配置即代码”到“代码即配置”的哲学跃迁,也映射出企业级应用从XML维护成本高、IDE支持弱、重构困难,向类型安全、编译期校验、面向对象封装、易于单元测试的现代化工程实践转型的必然趋势。此外,所有案例均基于Account业务场景,通过DAO-Service-Controller三层结构,贯穿演示了IoC容器如何管理Bean生命周期(实例化→属性填充→初始化→就绪→销毁)、如何解决循环依赖(通过三级缓存:singletonObjects、earlySingletonObjects、singletonFactories)、如何整合AOP(在IoC容器基础上叠加代理层),从而构成一个完整、健壮、可扩展的企业级轻量级容器解决方案。深入理解Day02,不仅是掌握Spring配置技术栈的关键一环,更是洞悉整个Spring生态(Spring MVC、Spring Boot、Spring Cloud)底层运行机理的基石所在。
慕酒
java Spring基础教程
Spring框架是Java企业级开发中最为重要、应用最广泛且生态最成熟的开源框架之一,其核心设计理念深刻影响了整个Java后端技术演进路径。本《Java Spring基础教程》系统性地涵盖了Spring框架从诞生背景到现代工程实践的完整知识脉络,是初学者构建扎实企业级开发能力的基石性学习资料。教程以“轻量级、非侵入式、松耦合、可测试”为设计哲学出发,深入剖析了Spring最核心的两大支柱控制反转(Inversion of Control, IoC)面向切面编程(Aspect-Oriented Programming, AOP)。IoC容器作为Spring的中枢神经,彻底改变了传统Java对象的创建管理方式——开发者不再需要手动通过new关键字实例化对象,而是将对象的生命周期交由Spring容器统一托管;容器依据配置元数据(XML、Java Config或注解)自动完成Bean的定义、实例化、依赖注入(Dependency Injection, DI)、初始化、后置处理及销毁全过程。依赖注入作为IoC的具体实现机制,支持构造器注入、Setter注入和字段注入三种主流方式,不仅显著降低模块间耦合度,更极大提升了代码的可维护性、可扩展性单元测试友好性。教程特别强调Bean的作用域(Singleton、Prototype、Request、Session等)、生命周期回调(InitializingBean/DisposableBean接口、@PostConstruct/@PreDestroy注解、InitializingBeanAware等)、循环依赖的检测与三级缓存解决方案,以及BeanFactoryApplicationContext两大容器体系的层级关系适用场景差异。在AOP部分,教程以“横切关注点分离”为切入点,详解代理模式(JDK动态代理CGLIB字节码增强)的底层原理,清晰界定切点(Pointcut)、通知(AdviceBefore、After、AfterReturning、AfterThrowing、Around)、切面(Aspect)、织入(Weaving)连接点(Join Point)五大核心概念,并通过真实日志记录、事务管理、权限校验、性能监控等典型业务场景演示如何基于@Aspect注解声明式地编写切面逻辑,避免重复代码污染核心业务。同时,教程深度解析Spring MVC的请求处理全流程从DispatcherServlet前端控制器接收HTTP请求开始,依次经过HandlerMapping定位处理器、HandlerAdapter适配执行、ModelAndView封装视图模型数据、ViewResolver解析视图名称、最终渲染响应返回客户端;并详述@RequestMapping及其派生注解(@GetMapping/@PostMapping等)、@RequestParam/@PathVariable/@RequestBody/@ResponseBody参数绑定机制、数据验证(@Valid + BindingResult)、异常统一处理(@ControllerAdvice + @ExceptionHandler)、RESTful风格API设计规范等关键能力。此外,教程还涵盖Spring传统XML配置现代Java Config(@Configuration/@Bean/@Import)双轨并行的配置体系,对比分析PropertyPlaceholderConfigurer、@Value、@ConfigurationProperties等外部化配置方案,以及Profile多环境配置管理策略。虽未直接展开Spring Boot内容,但已为其奠定坚实理论基础——包括自动配置原理(@EnableAutoConfiguration触发条件匹配、spring.factories加载机制)、起步依赖(Starter)设计理念、内嵌Tomcat/Jetty容器集成逻辑等均能在本教程的IoCAOP思想中找到源头。最后,《Spring基础教程.pdf》作为结构严谨、示例丰富、图文并茂的权威入门文档,不仅包含大量可运行的代码片段UML类图,更穿插了常见陷阱警示(如@Bean方法调用导致的单例失效、AOP代理失效场景、循环依赖误用等),帮助学习者建立正确的工程直觉调试思维。掌握本教程全部内容,意味着具备独立搭建高内聚、低耦合、易测试、可运维的Spring Web应用的能力,为后续深入Spring Security、Spring Data JPA、Spring Cloud微服务架构等高级主题打下不可替代的底层认知根基。
@醉酒青牛
spring中文开发参考手册
Spring中文开发参考手册是一份面向Java开发者、尤其是中初级Spring技术学习者实践者的系统性技术文档,其核心价值在于以中文语言全面、准确、结构化地呈现Spring框架的体系架构、核心原理与工程实践方法。该手册并非简单API速查表,而是融合了Spring 5.x主流版本(兼顾向后兼容Spring 6特性演进逻辑)的设计哲学、运行机制典型应用场景的深度指南。手册开篇即阐明Spring作为轻量级Java开源框架的本质定位——它并非全栈式容器,而是一个以“解耦”和“可测试性”为设计原点的分层架构平台,其影响力早已超越传统Java EE容器,成为现代云原生Java生态的事实标准基础设施。手册重点围绕IoC(Inversion of Control,控制反转)容器展开详尽解析不仅说明BeanFactoryApplicationContext两大核心接口的继承关系能力差异,更深入剖析DefaultListableBeanFactory的内部注册表结构(如beanDefinitionMap、singletonObjects、earlySingletonObjects等三级缓存机制),揭示Spring如何通过反射+工厂模式+策略模式实现对象生命周期的全托管;对依赖注入(Dependency Injection)的三种方式(构造器注入、Setter注入、字段注入)进行安全性、可测性、循环依赖处理能力的横向对比,并结合@Primary、@Qualifier、@Profile等注解说明复杂场景下的Bean装配策略。在AOP(Aspect-Oriented Programming)章节中,手册不局限于@AspectJ语法糖,而是从动态代理本质切入——详细图解JDK Proxy基于接口的代理机制CGLIB基于子类的字节码增强原理,对比二者在final类、private方法、性能开销上的根本差异;并通过@EnableAspectJAutoProxy源码级分析,说明Spring如何将AOP织入时机(编译期/类加载期/运行期)与Spring容器启动流程深度协同。针对Web开发主线,手册对Spring MVC执行流程进行七步拆解从DispatcherServlet初始化、HandlerMapping定位处理器、HandlerAdapter适配执行、ModelAndView数据封装,到ViewResolver视图解析、LocaleResolver国际化支持、ThemeResolver主题管理,每一环节均附带时序图关键接口契约说明;特别强调@ControllerAdvice@RestControllerAdvice在全局异常处理、数据绑定预处理、响应体统一封装中的企业级应用范式。事务管理部分则突破@Transactional声明式事务的表层用法,深入PlatformTransactionManager抽象体系,对比DataSourceTransactionManager、JtaTransactionManager、HibernateTransactionManager在不同持久化方案下的适配逻辑,详解传播行为(PROPAGATION_REQUIRED等七种)、隔离级别(ISOLATION_READ_COMMITTED等五级)、只读优化、超时回滚及嵌套事务的底层数据库交互机制。手册还前瞻性覆盖Spring Boot核心机制通过@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三大元注解溯源自动配置原理,剖析spring.factories文件加载机制Condition条件化装配(@ConditionalOnClass、@ConditionalOnMissingBean等)的决策树模型;详解application.yml多环境配置(dev/test/prod)的profiles激活链、外部化配置优先级(命令行参数 > 系统属性 > 配置文件 > 默认值)及@ConfigurationProperties类型安全绑定。此外,手册专章论述XML配置Java Config(@Configuration + @Bean)双轨并行的演进逻辑,指出纯注解开发虽为主流,但XML在遗留系统集成、复杂Bean引用(如ref parent="xxx")等场景仍具不可替代性。全手册贯穿大量生产级最佳实践如Bean作用域(Singleton/Prototype/Request/Session)的内存泄漏风险规避、@Lazy延迟初始化在循环依赖破除中的妙用、@Transactional失效的八大经典陷阱(自调用、非public方法、异常类型捕获、代理对象误用等)及解决方案。作为中文世界少有的兼顾理论深度工程厚度的权威参考资料,它实质构建了一条从Spring基础容器认知,到高并发事务保障,再到云原生微服务治理的完整能力跃迁路径,是每一位Java工程师夯实中间件内功、突破架构设计瓶颈不可或缺的知识基石。
Spring-Study:Spring学习项目
Spring-Study:Spring学习项目,是一个面向Java开发者、特别是初学者中级工程师的系统性实践工程,其核心目标在于通过可运行、可调试、可扩展的真实代码结构,深入理解Spring Framework生态体系的核心原理与主流用法。该项目虽命名简洁,但涵盖内容极为丰富,绝非简单的“Hello World”式Demo,而是围绕Spring技术栈五大支柱展开的完整知识闭环IoC(控制反转)容器机制、DI(依赖注入)实现原理、AOP(面向切面编程)动态代理织入逻辑、Spring MVC请求生命周期Web层架构设计,以及向现代化开发演进的关键跳板——Spring Boot自动配置约定优于配置范式。在IoC容器层面,项目必然包含BeanFactoryApplicationContext的对比使用,演示XML配置、@Configuration类+@Bean注解、以及@ComponentScan扫描机制等多种Bean定义方式;同时深入剖析Bean的作用域(Singleton/Prototype/Request/Session)、生命周期回调(InitializingBean/DisposableBean、@PostConstruct/@PreDestroy)、以及循环依赖三级缓存解决方案(singletonObjects、earlySingletonObjects、singletonFactories),帮助学习者从源码视角理解Spring如何安全地管理对象生命周期。依赖注入部分不仅覆盖构造器注入、Setter注入字段注入三种方式的适用场景优劣权衡,更强调“松耦合、高内聚”设计哲学在实际业务模块中的落地——例如UserService依赖UserRepository,而Repository又可被Mock或切换为JDBC/JPA/MyBatis实现,这种可插拔架构正是DI赋予系统的强大弹性。AOP模块则通过日志记录、事务管理、权限校验等典型横切关注点,展示JDK动态代理CGLIB字节码增强的技术差异,解析Pointcut表达式语法(execution、within、@annotation等)、Advice类型(@Before/@After/@Around/@AfterReturning/@AfterThrowing)的执行顺序异常传播机制,并结合TransactionInterceptor源码说明声明式事务如何借助AOPPlatformTransactionManager协同完成ACID保障。Spring MVC部分必定构建标准的DispatcherServlet前端控制器链路,涵盖HandlerMapping定位处理器、HandlerAdapter适配执行、ViewResolver视图解析全流程;同时实践RESTful风格接口设计、@RequestBody/@ResponseBodyHttpMessageConverter(如Jackson2ObjectMapper)的JSON序列化机制、数据校验(@Valid + BindingResult)、统一异常处理(@ControllerAdvice + @ExceptionHandler)及跨域配置(@CrossOrigin或CorsConfiguration)。尤为关键的是,项目虽以传统Spring起步,但必然集成Spring Boot作为现代Java Web开发的事实标准——通过spring-boot-starter-web、spring-boot-starter-data-jpa等Starter组件实现零XML配置启动,深入解读SpringApplication.run()背后的Environment准备、ApplicationContext初始化、自动配置类(@EnableAutoConfiguration)的条件化加载(@ConditionalOnClass、@ConditionalOnMissingBean)、以及外部化配置(application.properties/yml)Profile多环境支持。此外,标签中提及的Java EE并非指过时的EJB容器,而是强调Spring对JSR规范的兼容超越,如对JSR-330(@Inject)、JSR-250(@Resource)、JSR-303(Bean Validation)的原生支持,体现其作为轻量级Java EE替代方案的历史定位持续演进能力。整个项目结构(从压缩包名称Spring-Study-main可推断采用GitHub标准主干分支)应遵循Maven分层架构parent-pom统一版本管理,core模块封装通用工具抽象,web模块承载MVC控制器,servicedao模块分层解耦,test模块覆盖JUnit 5 + Mockito单元测试及SpringBootTest集成测试,甚至可能引入Actuator监控端点Swagger API文档自动化生成。综上所述,该学习项目实为一座贯通理论与工程实践的桥梁,既夯实Spring底层设计思想(如模板方法模式在JdbcTemplate中的应用、观察者模式在事件发布ApplicationEvent中的体现),又直面真实开发痛点(如N+1查询优化、事务传播行为REQUIRES_NEW陷阱、AOP代理失效场景规避),是掌握企业级Java后端开发能力不可或缺的基石性训练载体。
Friedrich ZHAO
spring-in-action-examples:Spring in Action Book(第 3 版)中的示例
Spring in Action》(第3版)是Spring框架领域极具代表性的经典实践指南,其配套示例代码库“spring-in-action-examples”不仅系统性地覆盖了Spring 2.5至3.0核心演进阶段的关键技术栈,更以高度可运行、结构清晰、注释详尽的工程实践方式,将抽象的框架原理转化为开发者可感知、可调试、可复用的真实场景。该示例集本质上是一套完整的Spring教学实验体系,其知识纵深横跨企业级Java应用开发的全生命周期从最基础的IoC容器初始化Bean生命周期管理,到复杂场景下的声明式事务控制;从传统XML驱动的配置范式,到早期基于注解(@Component、@Autowired、@Resource、@PostConstruct等)和Java Config(@Configuration、@Bean)的现代化配置演进;从MVC分层架构中HandlerMapping、Controller、ViewResolver的协同机制,到表单绑定、数据验证(JSR-303集成)、国际化(i18n)、文件上传异常统一处理等Web增强能力;从AOP底层代理机制(JDK动态代理 vs CGLIB字节码增强)的对比实现,到@AspectJ风格切面定义、切入点表达式(pointcut)的精准编写、通知类型(@Before、@After、@Around、@AfterReturning、@AfterThrowing)的语义差异执行顺序,再到AOP在日志审计、性能监控、安全拦截、缓存管理等横切关注点中的工业级落地模式。尤为关键的是,该示例深度整合了Spring测试模块(spring-test),通过@RunWith(SpringJUnit4ClassRunner.class)、@ContextConfiguration、@Transactional、@DirtiesContext等测试注解,构建出支持上下文缓存、事务回滚、Mock对象注入(如Mockito集成)、嵌入式数据库(HSQLDB/H2)及WebMvcTest的多层次自动化测试体系,彻底改变了传统Java EE中“写完代码即上线、出错靠日志猜”的低效调试范式。在工程构建层面,全部示例均采用Maven标准化管理,清晰呈现groupId/artifactId/version坐标体系、依赖传递性(如spring-core→commons-logging、spring-webmvc→spring-beans)、scope作用域(compile/test/provided)、profile多环境配置(dev/test/prod)、以及Jetty/Tomcat插件的无缝集成,使开发者得以在IDE中一键启动Web应用并实时观察Spring容器启动日志(BeanDefinition读取、BeanFactoryPostProcessor执行、InstantiationAwareBeanPostProcessor介入、InitializingBean回调、DisposableBean销毁钩子等完整生命周期事件)。此外,示例还涵盖Java EE生态的互操作实践如JNDI资源查找、JTA分布式事务桥接、Servlet 2.5规范兼容性、JSP/Thymeleaf模板引擎切换、以及对Hibernate/JPA数据访问层的封装抽象(JdbcTemplate、HibernateTemplate、SimpleJpaRepository)。所有这些内容并非孤立存在,而是通过精心设计的业务场景——如音乐商店(MusicStore)、博客系统(BlogApp)、任务管理(TaskManager)等——有机串联,每个模块都体现“约定优于配置”“面向接口编程”的Spring哲学。例如,在依赖注入部分,不仅演示setter注入构造器注入的语法差异,更深入剖析循环依赖三级缓存解决方案、@Lazy延迟加载对启动性能的影响、@Primary@Qualifier的歧义消解策略;在AOP示例中,不仅实现简单日志切面,更通过@Around环绕通知结合StopWatch实现方法级性能埋点,并SLF4J+Logback集成输出结构化耗时报告;在Spring MVC中,通过@Valid配合BindingResult展示服务端校验错误消息国际化联动机制,再通过@ModelAttribute预填充表单模型,体现控制器层的高内聚设计。综上所述,“spring-in-action-examples”远不止是书本的代码附录,它是一座立体化的Spring知识图谱既承载着Spring 3时代的技术烙印(如对Java 5泛型、注解、并发包的深度适配),又为后续Spring 4/5/6的函数式配置、响应式编程(WebFlux)、云原生支持(Spring Boot自动配置原理)奠定了坚实认知基础;既是初学者理解“控制反转”本质的启蒙沙盒,也是资深工程师重构遗留系统、设计可测试架构、实施微服务治理前必经的思维训练场。其每一行代码背后,都凝结着Spring团队对松耦合、高内聚、易扩展、可维护这一软件工程终极目标的持续求索。
温暖如故