前言
从我在教学视频的帮助下写的第一个项目开始,我就了解到了Spring对我这个写Java做后端的人来说的重要性。
想阅读Spring源码也不是一天两天了,毕业找工作时也背了很多Spring的八股文,显然我只通过八股了解了最外面那层晦涩难懂的机制,当然那时的我也明白这一点,印象中至少有两三次从网上搜索“Spring源码阅读”这样的尝试,不过最终都是在不知如何下手和繁忙做先锋的借口武器中败下阵来。当时校招面京东时感觉聊的还不错就顺便问了面试官如何阅读Spring源码这个试图表现自己拥有良好学习态度的问题,哈哈哈。
本来准备是结合最近在内网上看的几篇Spring文章(大多都是六七年前的),在这里给出一个大致的Spring阅读和总结的思路,结果还是觉得看框架一定要先看完再开始总结,因此这里开篇只介绍一下对源码springframework编译时的环境配置和问题解决。
环境安装
这里说一下我的系统为Mac OS,使用的IDE是IntelliJ IDEA。按照Spring源码编译官方文档来: github.com/spring-proj…;
首先我们开始搭建开发环境,从官网文档中看到我们需要搭建以下环境:
- Java环境变量指向JDK17的Java环境;
- Gradle编译环境,同时需要保证能被Gradle检测到的GIT、JDK17以及JDK21;
Java环境
我们从Oracle官网下载JDK17: download.oracle.com/java/17/lat…, 然后我们去环境变量文件里设置Java环境变量,Mac系统默认的环境变量文件可以看看~/.bash_profile, 如果像我一样安装了oh-my-szh终端环境的可以找~/.zshrc, 两个都找不到的直接新建一个文件也行。无论如何,我们在文件里添加JDK17的HOME地址
export JAVA_HOME_17=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home
export PATH=$PATH:$M2_HOME/bin:$JAVA_HOME_17/bin
如果系统只有一个JDK版本或者想让JDK17当作默认版本的话,可以把上面的路径直接设置为JAVA_HOME;反之,如果系统里有多个JDK版本而且不想让JDK17作为默认版本的话,可以通过变量别名的方式每次需要特定版本的时候输入别名来实现:
alias java8='export JAVA_HOME=$JAVA_HOME'
alias java17='export JAVA_HOME=$JAVA_HOME_17'
注意在编译springframework前执行一次java17, 这样让系统默认的JDK版本为JDK17。
Gradle环境
springframework通过Gradle进行编译,官网下载:gradle.org/releases;
同样在环境变量文件中配置Gradle环境变量:
export GRADLE_HOME=/Library/gradle-8.1.1
export PATH="$GRADLE_HOME/bin:$PATH"
查看Gradle版本:
IDE环境
设置编译器的Gradle和JDK版本,这样可以直接使用编译器的快捷按钮进行编译:
在编译器中设置项目的JDK版本:
引入项目
我们在GitHub里fork一下spring-projects/spring-framework项目,fork的时候要注意只拷贝main分支这里不要勾选,因为我们看源码从稳定版看需要切换稳定版分支。
然后把个人项目克隆到本地:
git clone git@github.com:xxxx/spring-framework.git //xxxx为自己的GitHub账号
cd spring-framework
我们调试代码尽量在项目的稳定版本上进行,直接切换分支为当前稳定版本,在本地稳定版本上调试:
git checkout -b v6.0.2
git pull origin v6.0.2
也可以基于远程分支新建一个本地调试分支:
git checkout -b feature/sample origin/6.0.x
git push origin feature/sample
git branch --set-upstream-to=origin/feature/sample feature/sample //解决push失败
完成分支切换后,我们在目录里发现有个文件叫import-into-idea.md,这是官方指导我们把项目引入到IDEA中的文件,我们打开发现:
## Steps
_Within your locally cloned spring-framework working directory:_
1. Precompile `spring-oxm` with `./gradlew :spring-oxm:compileTestJava`
2. Import into IntelliJ (File -> New -> Project from Existing Sources -> Navigate to directory -> Select build.gradle)
3. When prompted exclude the `spring-aspects` module (or after the import via File-> Project Structure -> Modules)
4. Code away
按照这个步骤来即可成功引入项目到本地。
编译
在完成上面环境搭建后,我们可以进行源码编译,IDEA工具化方式编译或者终端Gradle命令编译均可以:
./gradlew build
调试
阅读源码时需要不断的对刚看完的源码进行测试和调试以加深理解,首先我们在项目中新建一个用于调试的module,file -> new -> module:
一般刚开始是对Spring获得Bean的功能进行测试,我们在新模块下新建两个package,一个存放@Component🎍的Bean,一个存放@Service注解的Bean,
com.zhoukekexi.spring.sample.start.config.StartSampleConfig:
@Component
public class StartSampleConfig {
@Bean
public String name() {
return "Hello world!";
}
}
com.zhoukekexi.spring.sample.start.service.StartSampleService:
@Service
public class StartSampleService {
public void sampleMethod() {
System.out.println("你好, 世界!");
}
}
然后再新建一个Application类用于获得Bean:
com.zhoukekexi.spring.sample.start.SpringStartSampleApplication:
@ComponentScan("com.zhoukekexi.spring.sample.**")
public class SpringStartSampleApplication {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringStartSampleApplication.class);
Object name = context.getBean("name");
System.out.println(name);
StartSampleService service = context.getBean(StartSampleService.class);
service.sampleMethod();
}
}
对main()方法进行调试,可以看见成功获得Bean:
问题整理
1、问题:freeCompilerArgs.addAll(List.of("-Xsuppress-version-warnings", "-Xjsr305=strict", "-opt-in=kotlin.RequiresOptIn"));错误:找不到符号
解决:这个问题应该是没有在打开项目编译前使用别名指定java版本为JDK17,可以直接在gradle.properties文件里加上
org.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home
2、问题:No matching toolchains found for requested specification: {languageVersion=21, vendor=any, implementation=vendor-specific}.
解决:开头我们也引入过官方文档介绍的gradle需要的toolchains里有JDK21,这个报错应该是环境里么有安装JDK21导致的,有两种解决办法,一种是安装JDK21并添加到环境中,第二种是在spring-core.gradle文件里将multiRelease的指定版本里的21删掉:
把图里改成:
即可解决问题。