一. 前言

Spring Boot 3 RELEASE版本于 2022年11月24日 正式发布,相信已经有不少同学开始准备新版本的学习了,不过目前还不建议在实际项目中做升级,毕竟还有很多框架和中间件没出适配版本。此次Spring Boot里程碑的升级也要求了最低JDK 17Spring Framework 6 ,其核心框架的 Spring 也在 2022年11月16日 迎来了从 5.3.x6.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 ,仅需三步:

  1. Precompile spring-oxm with ./gradlew :spring-oxm:compileTestJava

    Windows 环境 CMD 输入 gradlew :spring-oxm:compileTestJava 先执行 spring-oxm 的预编译

  2. 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 完成编译

  3. 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-corespring-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

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 源码编译和高效阅读源码技巧分享的更多相关文章

  1. 如何在 GitHub 上高效阅读源码?

    原文链接: 如何在 GitHub 上高效阅读源码? 之前听说过一个故事,一个领导为了提高团队战斗力,把团队成员集中起来,搞封闭开发,重点还是在没有网的条件下. 结果就是一个月过去了,产出基本为零. 我 ...

  2. JDK1.8源码分析02之阅读源码顺序

    序言:阅读JDK源码应该从何开始,有计划,有步骤的深入学习呢? 下面就分享一篇比较好的学习源码顺序的文章,给了我们再阅读源码时,一个指导性的标志,而不会迷失方向. 很多java开发的小伙伴都会阅读jd ...

  3. Spring是如何整合JUnit的?JUnit源码关联延伸阅读

    上一篇我们回答了之前在梳理流程时遇到的一些问题,并思考了为什么要这么设计. 本篇是<如何高效阅读源码>专题的第十二篇,通过项目之间的联系来进行扩展阅读,通过项目与项目之间的联系更好的理解项 ...

  4. Java工程师阅读源码的一些见解

    一.为何阅读源码 就是说,通过阅读源码能给你带来什么好处. 学习如何从需求-设计-实现,开阔你的思维,提升你的架构设计能力: 帮助更好地理解原理和架构设计: 帮助更快地定位线上问题BUG 可以根据自己 ...

  5. spring5源码编译过程中必经的坑

    spring源码编译流程:Spring5 源码下载 第 一 步 : https://github.com/spring-projects/spring-framework/archive/v5.0.2 ...

  6. 从ApacheTomcat架构谈面试到源码编译环境v10.0.12

    概述 开启博客分享已近三个月,感谢所有花时间精力和小编一路学习和成长的伙伴们,有你们的支持,我们继续再接再厉 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 Tomcat官 ...

  7. 非寻常方式学习ApacheTomcat架构及10.0.12源码编译

    概述 开启博客分享已近三个月,感谢所有花时间精力和小编一路学习和成长的伙伴们,有你们的支持,我们继续再接再厉 **本人博客网站 **IT小神 www.itxiaoshen.com 定义 Tomcat官 ...

  8. SSH/SSL 源码编译安装简易操作说明

    环境:CentOS 6.7 安全加固需求,由于某盟扫描系统主机有SSL系列漏洞,客户要求必须修复: 解决方案:将SSH/SSL升级到最新版本,删除SSL旧版本(实测不删除旧版本某盟扫描无法通过). 当 ...

  9. Nginx+Php-fpm+MySQL+Redis源码编译安装指南

    说明:本教程由三部分组成如下: 1.      源码编译安装Nginx 2.      源码编译安装php以及mysql.redis扩展模块 3.      配置虚拟主机 文中所涉及安装包程序均提供下 ...

  10. nginx1.11.9 apt即源码编译各平台测试

    测试系统:ubuntu16.04 server,debian8.7 netinstall,centos7 mini. 系统配置:使用virtualbox安装,内存1G,cpu单核,物理CPU  i5- ...

随机推荐

  1. 驱动开发:通过Async反向与内核通信

    在前几篇文章中给大家具体解释了驱动与应用层之间正向通信的一些经典案例,本章将继续学习驱动通信,不过这次我们学习的是通过运用Async异步模式实现的反向通信,反向通信机制在开发中时常被用到,例如一个杀毒 ...

  2. 自学Spring

    Spring官网地址https://spring.io/ springManven官网地址:https://mvnrepository.com------------------------ spri ...

  3. 分布式存储系统之Ceph集群存储池、PG 与 CRUSH

    前文我们了解了ceph集群状态获取常用命令以及通过ceph daemon.ceph tell动态配置ceph组件.ceph.conf配置文件相关格式的说明等,回顾请参考https://www.cnbl ...

  4. HDU1423 Greatest Common Increasing Subsequence (DP优化)

    LIS和LCS的结合. 容易写出方程,复杂度是nm2,但我们可以去掉一层没有必要的枚举,用一个变量val记录前一阶段的最优解,这样优化成nm. 1<=k<j,j增加1,k的上界也增加1,就 ...

  5. Docker容器技术基础

    Docker基础 目录 Docker基础 容器(Container) 传统虚拟化与容器的区别 Linux容器技术 Linux Namespaces CGroups LXC docker基本概念 doc ...

  6. Sentinel安装教程【Linux+windows】

    一.Sentinel的简介 Sentinel是阿里巴巴出品的一款流控组件,它以流量为切入点,在流量控制.断路.负载保护等多个领域开展工作,保障服务可靠性. 如果你学过netflix公司旗下的Hystr ...

  7. 后端框架学习3------SpringMVC

    springMVC学习笔记 官方文档地址:https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html# ...

  8. C语言------选择结构

    仅供借鉴.仅供借鉴.仅供借鉴(整理了一下大一C语言每个章节的练习题.没得题目.只有程序了) 文章目录 1 .实训名称 2 .实训目的及要求 3 .源代码及运行截图 4.小结 1 .实训名称 实训4:选 ...

  9. FileNotFoundError: Could not find module libmxnet.dll

    解决方法:把CUDA的bin目录下的dll文件全部复制到libmxnet.dll所在的目录 问题原因:libmxnet.dll引用了一些CUDA的dll,但是找不到路径.

  10. C# 8.0 添加和增强的功能【基础篇】

    .NET Core 3.x和.NET Standard 2.1支持C# 8.0. 一.Readonly 成员 可将 readonly 修饰符应用于结构的成员,来限制成员为不可修改状态.这比在C# 7. ...