Spring 6 源码编译和高效阅读源码技巧分享
一. 前言
Spring Boot 3
RELEASE版本于 2022年11月24日 正式发布,相信已经有不少同学开始准备新版本的学习了,不过目前还不建议在实际项目中做升级,毕竟还有很多框架和中间件没出适配版本。此次Spring Boot
里程碑的升级也要求了最低JDK 17
和 Spring Framework 6
,其核心框架的 Spring 也在 2022年11月16日 迎来了从 5.3.x
到 6.0.x
重大版本升级,借着这个机会,写一篇关于 Spring 6 源码编译和如何高效阅读 Spring 源码的教程。
二. 环境声明
Spring源码编译官方文档:https://github.com/spring-projects/spring-framework/wiki/Build-from-Source
根据官方文档描述, Spring 6 需要
JDK 17
。
基础环境 | 版本 | 本地路径 |
---|---|---|
操作系统 | Windows 11 | - |
Spring源码 | 6.0.2 | D:\SourceCode\spring-framework |
Java环境 | JDK 17 | D:\Java\jdk-17.0.3.1 |
编译工具 | Gradle 7.6 | D:\softs\gradle-7.6 |
开发工具 | IDEA 2022.2.3 | - |
三. JDK 安装
1. 下载JDK17
下载链接: https://download.oracle.com/java/17/latest/jdk-17_windows-x64_bin.exe
下载后静默安装即可,按需修改 JDK 路径(D:\Java\jdk-17.0.3.1)
2. 配置环境变量(可忽略)
配置环境 JDK 环境变量非必须!考虑到大多数人因为老项目JAVA_HOME配置JDK8的情况,下文是通过设置 Gradle 指定 JDK 版本方式。
添加系统变量 JAVA_HOME = D:\Java\jdk-17.0.3.1
添加Path:%JAVA_HOME%\bin
验证:java -version
四. Gradle 安装
1. 下载Gradle
下载地址:https://gradle.org/releases
下载解压到指定目录(D:\softs\gradle-7.6)
2. 配置环境变量
添加系统变量:GRADLE_HOME=D:\softs\gradle-7.6
添加至Path路径(%GRADLE_HOME%\bin)
查看版本 gradle -v
3. 配置镜像仓库
在gradle安装位置(D:\softs\gradle-7.6\init.d) 目录下新建 init.gradle 文件
参考阿里云官方gradle配置指南:https://developer.aliyun.com/mvn/guide ,init.gradle 完整内容如下
allprojects {
repositories {
maven { url 'file:///D:/data/.m2/repository'} // 本地仓库地址,如果没有依次向下寻找
maven { url "https://maven.aliyun.com/repository/public" }
mavenLocal()
mavenCentral()
}
buildscript {
repositories {
maven { url 'https://maven.aliyun.com/repository/public' }
mavenLocal()
mavenCentral()
}
}
}
五. 源码编译
1. 获取Spring源码
不建议zip包方式下载源代码,具体看官方issue:https://github.com/spring-projects/spring-framework/issues/24467
IDEA 选择 File → New → Project from Version Control 输入Spring源码仓库地址:
源 | 地址 | 备注 |
---|---|---|
Github | https://github.com/spring-projects/spring-framework.git | 速度慢 |
GitCode | https://gitcode.net/mirrors/spring-projects/spring-framework.git | 国内镜像,速度极快 |
IDEA源码获取完成之后,因为当前时间最新稳定版tag是v6.0.2版本 ,所以还需要进行分支切换:
git checkout -b v6.0.2
git pull origin v6.0.2
2. 环境设置
IDEA设置
File → Settings → Build,Execution,Deployment → Build Tools → Gradle
build.gradle
找到 repositories 配置节点,新增阿里云镜像仓库地址
maven { url "https://maven.aliyun.com/repository/public" } // 阿里云镜像仓库
settings.gradle
找到 repositories 配置节点,新增阿里云镜像仓库地址
maven { url "https://maven.aliyun.com/repository/public" } // 阿里云镜像仓库
gradle.properties
项目内gradle.properties
配置文件添加java路径org.gradle.java.home=D:\Java\jdk-17.0.3.1
3. 编译步骤
在完成上述的源码导入和相关设置之后,就可以进行源码编译了。
参考IDEA导入说明文档 import-into-idea.md
,仅需三步:
Precompile
spring-oxm
with./gradlew :spring-oxm:compileTestJava
Windows 环境 CMD 输入
gradlew :spring-oxm:compileTestJava
先执行spring-oxm
的预编译Import into IntelliJ (File -> New -> Project from Existing Sources -> Navigate to directory -> Select build.gradle)
File → New → Project from Existing Sources → Select File or Directory to import 选择
build.gradle
点击 OK 完成编译When prompted exclude the
spring-aspects
module (or after the import via File-> Project Structure -> Modules)
六. 测试案例
在完成上文 Spring 源码编译之后,Congratulations ! 接下来新增一个示例模块来依赖工程中的其它 spring 模块做个简单的测试。
1. 新增模块
File → Module 新增 spring-sample
示例模块
2. 添加依赖
在 spring-sample
模块下的 build.gradle
新增 spring-context
依赖,它是包含了 spring-core
、 spring-bean
和 IoC容器等Spring 运行时上下文的依赖。
api(project(":spring-context"))
3. 测试代码
代码结构
/**
* 人接口
*/
public interface IPersonService {
/**
* 说
*/
void speak();
}
/**
* 中国人
*/
@Service
@Primary
public class ChineseService implements IPersonService {
@Override
public void speak() {
System.out.println("我会说中文");
}
}
/**
* 美国人
*/
@Service
public class AmericanService implements IPersonService {
@Override
public void speak() {
System.out.println("I can speak English");
}
}
/**
* 启动测试类
*/
@ComponentScan("com.youlai.spring.sample.**")
public class SpringSampleApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
SpringSampleApplication.class
);
IPersonService personService = context.getBean(IPersonService.class);
personService.speak();
}
}
4. 测试结果
image-20221210232239371
七. 源码阅读
本章节就基于编译好的 Spring 源码环境进行源码调试,为了方便下面就基于上章节的测试案例来对 getBean
源码流程分析,后续会更新出 Spring 源码阅读系列文章。
1. getBean 源码
- 快速定位: 通过 Debug (
F7
)可以很清晰看到详细的调用栈
image-20221210230131704
加深理解记忆: 基于调用栈绘制时序图(IDEA的
PlantUML
插件)时序图源文件:https://gitee.com/youlaiorg/spring-framework/blob/master/doc/diagram/getBean.puml
getBean时序图
深入概念原理
时序图反映了在
getBean()
调用链中DefaultListableBeanFactory
承担着核心角色,甚至可以说是 Spring 最核心的一个BeanFacory
实现 ,也被称为 Spring 的 “发动机”,所以其重要性是学习 Spring 源码的必修课。DefaultListableBeanFactory
: 可枚举的Bean工厂。
通过类注释我们可以了解到:DefaultListableBeanFactory
是一个成熟的bean工厂;包含了 bean 定义元数据(beanDefinitionMap),提供了Bean定义的注册和获取方法;管理已存在的Bean实例,而不是基于Bean定义去创建新实例。
2. todo
后续更新 Spring 6
源码阅读系列 @有来技术。
八. 问题整理
在编译过程中,因环境不同每个人可能遇到的问题也都不同,但是总结出来的都是没按照官方文档要求或者自己粗心所致,下面就总结编译中遇到常见的问题,也希望大家在留言区把自己遇到问题记录下。
1. 问题一
报错详情
D:\SourceCode\spring-framework>gradlew :spring-oxm:compileTestJava > Task :buildSrc:compileJava FAILED
D:\SourceCode\spring-framework\buildSrc\src\main\java\org\springframework\build\KotlinConventions.java:44: 错误: 找不到符号
freeCompilerArgs.addAll(List.of("-Xsuppress-version-warnings", "-Xjsr305=strict", "-opt-in=kotlin.RequiresOptIn"));
^
符号: 方法 of(java.lang.String,java.lang.String,java.lang.String)
位置: 接口 java.util.List
1 个错误 FAILURE: Build failed with an exception.
解决方案
gradlew :spring-oxm:compileTestJava info
查看使用 JDK 的版本是不是17,如果不是请在配置文件gradle.properties
添加:org.gradle.java.home=D:\Java\jdk-17.0.3.1
2. todo
欢迎大家留言区补充或提问~
九. 结语
本篇从 Spring 6 编译依赖的基础环境搭建(JDK17和Gradle)开始、根据官方文档编译源码、在工程新增示例模块测试、以及最后通过对getBean的源码调试,绘制时序图和类注释辅助手段来掌握高效阅读Spring源码技巧。还有一点需要提醒,一定要带着一个明确的目的去看源码,不要被动式的为了学习而学习,不然很容易在知识的海洋里呛水。最后预祝大家编译成功,掌握到属于自己高效阅读源码的方式。
持续更新~
附. 源码
Spring 6 编译源码仓库地址: https://gitee.com/youlaiorg/spring-framework
Spring 6 源码编译和高效阅读源码技巧分享的更多相关文章
- 如何在 GitHub 上高效阅读源码?
原文链接: 如何在 GitHub 上高效阅读源码? 之前听说过一个故事,一个领导为了提高团队战斗力,把团队成员集中起来,搞封闭开发,重点还是在没有网的条件下. 结果就是一个月过去了,产出基本为零. 我 ...
- JDK1.8源码分析02之阅读源码顺序
序言:阅读JDK源码应该从何开始,有计划,有步骤的深入学习呢? 下面就分享一篇比较好的学习源码顺序的文章,给了我们再阅读源码时,一个指导性的标志,而不会迷失方向. 很多java开发的小伙伴都会阅读jd ...
- Spring是如何整合JUnit的?JUnit源码关联延伸阅读
上一篇我们回答了之前在梳理流程时遇到的一些问题,并思考了为什么要这么设计. 本篇是<如何高效阅读源码>专题的第十二篇,通过项目之间的联系来进行扩展阅读,通过项目与项目之间的联系更好的理解项 ...
- Java工程师阅读源码的一些见解
一.为何阅读源码 就是说,通过阅读源码能给你带来什么好处. 学习如何从需求-设计-实现,开阔你的思维,提升你的架构设计能力: 帮助更好地理解原理和架构设计: 帮助更快地定位线上问题BUG 可以根据自己 ...
- spring5源码编译过程中必经的坑
spring源码编译流程:Spring5 源码下载 第 一 步 : https://github.com/spring-projects/spring-framework/archive/v5.0.2 ...
- 从ApacheTomcat架构谈面试到源码编译环境v10.0.12
概述 开启博客分享已近三个月,感谢所有花时间精力和小编一路学习和成长的伙伴们,有你们的支持,我们继续再接再厉 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 Tomcat官 ...
- 非寻常方式学习ApacheTomcat架构及10.0.12源码编译
概述 开启博客分享已近三个月,感谢所有花时间精力和小编一路学习和成长的伙伴们,有你们的支持,我们继续再接再厉 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 Tomcat官 ...
- SSH/SSL 源码编译安装简易操作说明
环境:CentOS 6.7 安全加固需求,由于某盟扫描系统主机有SSL系列漏洞,客户要求必须修复: 解决方案:将SSH/SSL升级到最新版本,删除SSL旧版本(实测不删除旧版本某盟扫描无法通过). 当 ...
- Nginx+Php-fpm+MySQL+Redis源码编译安装指南
说明:本教程由三部分组成如下: 1. 源码编译安装Nginx 2. 源码编译安装php以及mysql.redis扩展模块 3. 配置虚拟主机 文中所涉及安装包程序均提供下 ...
- nginx1.11.9 apt即源码编译各平台测试
测试系统:ubuntu16.04 server,debian8.7 netinstall,centos7 mini. 系统配置:使用virtualbox安装,内存1G,cpu单核,物理CPU i5- ...
随机推荐
- prometheus和granfana企业级监控实战v5
文件地址:https://files.cnblogs.com/files/sanduzxcvbnm/prometheus和granfana企业级监控实战v5.pdf
- 史上最全的selenium三大等待介绍
一.强制等待 1.设置完等待后不管有没有找到元素,都会执行等待,等待结束后才会执行下一步 2.实例 driver = webdriver.Chrome() driver.get("https ...
- 华为网关交换机开启DHCP server服务
华为网关交换机可以配置基于全局地址池的DHCP服务器,也可以配置基于接口地址池的DHCP服务器,本人比较倾向于配置基于接口地址池的DHCP服务器,因此在这里只介绍后者. 第一步:开启DHCP功能 [S ...
- 虚拟线程 - VirtualThread源码透视
前提 JDK19于2022-09-20发布GA版本,该版本提供了虚拟线程的预览功能.下载JDK19之后翻看了一下有关虚拟线程的一些源码,跟早些时候的Loom项目构建版本基本并没有很大出入,也跟第三方J ...
- POJ3280 Cheapest Palindrome (区间DP)
dp[i][j]表示将字符串子区间[i,j]转化为回文字符串的最小成本. 1 #include<cstdio> 2 #include<algorithm> 3 #include ...
- Python函数-2V2
一.导入 $$ f ( x , y ) = 2 x + 3 y $$ 上面括号里面的就是数学公式里的自变量,自变量就相当于函数里的参数. 二.为什么要有参数 如果一个大楼里有两种尺寸不一的窗户,显然在 ...
- java的分页原理详解
首先先创建一个Student实体类. import java.io.Serializable; import java.util.Map; public class Student implement ...
- VMware vSphere 8.0 正式版下载
请访问原文链接:https://sysin.org/blog/vmware-vsphere-8/,查看最新版.原创作品,转载请保留出处. 作者主页:www.sysin.org vSphere 8.0 ...
- 01-MySQL8主从详解
主从原理 master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中:slave服务器会在一定时间间隔内对master二进制日志进行探测其是 ...
- CQOI2015任务查询系统
题目链接 主席树. 把区间的影响挂在左端点与右端点,建树时顺便对应的插入与删除. 维护一段值域区间的和与数字个数,查询时要注意与第k大的数相同的数可能有很多. 复杂度O(nlogn) #include ...