Spring 源码系列(2): 手把手搭建 Spring 源码调试环境
上篇我们定好了路线,这篇是后面所有源码追踪的地基:没有能断点的环境,读源码就是纸上谈兵。目标只有一个——让你在本机把 spring-framework 跑起来,并写一个最小 Demo 断进去。
一、为什么要搭调试环境
看博客、截图、PDF,当时看懂,三天就忘。真正吃透源码的方式只有一种:能断点、能单步、能看调用栈。
本篇做完,你应该能:
- 在本机导入并编译 spring-framework 源码;
- 写一段最小的 Spring 启动代码;
- 在
refresh()上打断点,一路 Step Into 跟下去。
二、环境前置
| 依赖 | 建议版本 | 说明 |
|---|---|---|
| JDK | 8(或 11) | Spring 5.3 对 JDK 8 最稳,避免 JDK 17 的模块系统坑 |
| Git | 任意新版 | 用于拉源码 |
| IntelliJ IDEA | 2020.3+ | 社区版足够 |
| 内存 | 8G+ | Gradle 构建吃内存 |
| Gradle | 不需要装 | 仓库自带 gradle wrapper(./gradlew),直接用 |
关键提醒:不要自己另外装 Gradle。仓库根目录的 gradlew / gradlew.bat 会自动下载匹配版本,自己装错版本反而报错。
三、第一步:拉取源码
强烈建议基于稳定 tag,别直接拉 master(master 可能含未发布的破坏性改动)。
# 方式一:GitHub(慢可挂代理)
git clone -b 5.3.x https://github.com/spring-projects/spring-framework.git
# 方式二:国内 Gitee 镜像(速度快)
git clone -b 5.3.x https://gitee.com/mirrors/Spring-Framework.git
cd spring-framework
git checkout v5.3.39 # 选一个具体 release tag,结果更可复现
5.3.x 是 5.3 的维护分支;若想完全可复现,直接 checkout 具体 tag(如 v5.3.39)。
四、第二步:预编译关键模块(很多人卡在这)
Spring 官方导入指南要求先编译 spring-oxm 的测试代码——它用 AspectJ 生成部分类,不预先编译,IDEA 导入后会报一堆找不到符号。
# Mac / Linux
./gradlew :spring-oxm:compileTestJava
# Windows
gradlew.bat :spring-oxm:compileTestJava
这一步很快,几分钟内结束。
五、第三步:导入 IDEA
Open or Import→ 选择spring-framework根目录下的build.gradle(注意是 Gradle 不是 Maven,别选pom.xml);- 勾选
Use auto-import(自动导入依赖变化); - 等待 IDEA 下载依赖 + 建立索引,首次较慢(10~30 分钟,看网速);
- 导入完成后,项目结构里能看到
spring-core、spring-beans、spring-context等模块。
若 IDEA 提示 Kotlin 未配置,去 Plugins 装 Kotlin 插件,或执行 ./gradlew :spring-core:compileKotlin。
六、第四步:写最小调试 Demo
不要改框架代码。最省事的方案是借用框架自带的 test 源集,它天然依赖所有 Spring 模块。
在 spring-context 模块的 src/test/java 下新建包 com.demo,写三个类:
// AppConfig.java
@Configuration
@ComponentScan("com.demo")
public class AppConfig {
}
// DemoBean.java
@Component
public class DemoBean {
public void hello() {
System.out.println("hello spring");
}
}
// Main.java
public class Main {
public static void main(String[] args) {
// 在这里打断电,跟进 refresh()
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
ctx.getBean(DemoBean.class).hello();
}
}
如果你的 IDEA 不允许在 test 源集里跑 main,也可以新建一个独立 Gradle 子模块,在 build.gradle 里 implementation(project(":spring-context")) 后照写即可。
七、第五步:断点调试
- 在
org.springframework.context.support.AbstractApplicationContext.refresh()第一行打断电; - 右键
Main.main()→Debug; - 程序停在断点后,用 IDEA 的 Call Stack 窗口看调用链,
Step Into(F7)逐行跟进; - 这几个方法是后面几篇的重点,建议现在就逐个点进去扫一眼:
obtainFreshBeanFactory():加载并注册 BeanDefinition;invokeBeanFactoryPostProcessors():执行 BeanFactoryPostProcessor;registerBeanPostProcessors():注册 BeanPostProcessor;finishBeanFactoryInitialization():实例化所有非懒加载单例 Bean。
能跑到这里并看懂 refresh() 在干嘛,本篇目标就达成了。
八、常见问题排查
- Kotlin not configured:装 Kotlin 插件,或
./gradlew :spring-core:compileKotlin; - 构建 OOM / 卡死:给 IDEA 的 Gradle、Compiler 加大堆,例如
-Xmx2g; - JDK 版本报错:确认 Project SDK = JDK 8,且
gradle.properties里org.gradle.java.home指向 JDK 8; - 索引一直不结束:耐心等;或
File → Invalidate Caches / Restart; - 断点进不去:确认跑的是源码模块里的
main,而不是你引入的外部springjar 包。
九、小结
到这一步,你已经能在本地断点调试 Spring 源码——这是后续每一篇「源码追踪」的前提,我写的每一步你都能自己复现。
下一篇我们正式进入 IoC 容器,从最基础也最容易混淆的问题讲起:BeanFactory 与 ApplicationContext 到底差在哪。
如果这篇帮你少踩了坑,欢迎收藏 + 关注。下篇见。
更多推荐




所有评论(0)