02. spring源码编译
Posted java技术探秘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了02. spring源码编译相关的知识,希望对你有一定的参考价值。
本文代码的gitee仓库链接:https://gitee.com/funcy/spring-framework.
在获取spring源码[1]一文中,我们成功地将spring源码导入了gitee仓库中,并且基于v5.2.2.RELEASE
创建了分支v5.2.2.RELEASE_learn
,接下来我们就基于该分支对spring源码进行编译。
为何要编译spring源码?
我们编译spring源码,主要是为了调试。虽说jar包的形式也可调试,但是如果我们边在源码上做注释,边调试,甚至修改源码实现我们想要的功能,岂不美哉?
1. 在命令行中编译
关于如何编译spring源码,spring项目早有说明,如果你想在命令行中构建,可以参考Build-from-Source[2],这里我将我的编译过程记录如下:
1.1 获取源码
$ git clone https://gitee.com/xxx/spring-framework
$ cd spring-framework
1.2 配置gradle
gradle构建时,会自动下载对应的gradle版本,所以我们可以不必额外下载gradle。但由于国内网络下载gradle的jar实在太慢,因此我们需要给gradle加个速,相关配置如下:
在个人home目录下,创建.gradle文件夹,然后创建init.gradle文件:
$ cd ~
$ mkdir .gradle
$ cd .gradle
$ touch init.gradle
在init.gradle中添加如下内容:
allprojects {
repositories {
maven {
url "https://maven.aliyun.com/repository/public"
}
maven {
url "https://maven.aliyun.com/repository/jcenter"
}
maven {
url "https://maven.aliyun.com/repository/spring"
}
maven {
url "https://maven.aliyun.com/repository/spring-plugin"
}
maven {
url "https://maven.aliyun.com/repository/gradle-plugin"
}
maven {
url "https://maven.aliyun.com/repository/google"
}
maven {
url "https://maven.aliyun.com/repository/grails-core"
}
maven {
url "https://maven.aliyun.com/repository/apache-snapshots"
}
}
}
gradle配置就完成了。
1.3 运行构建命令
在spring-framework目录下,运行构建命令:
./gradlew build
接下来就是漫长的等待了。第一次构建,下载的依赖会比较多,构建时长完全取决于你的网速了。
2. 在idea中编译
上面介绍了如何在命令行中构建spring源码,但一般来说,这样直接构建的人并不多,绝大多数人都是在开发工具中构建,毕竟构建完成后可以用来运行自己的测试代码,多好!由于本人是用idea开发,因此这里只介绍如何在idea中编译spring源码。
关于如何在idea,spring可以参考import-into-idea[3],这里给出我的编译过程:
2.1 配置gradle
与命令行编译相同,idea在构建时,会自动下载对应的gradle版本,所以我们可以不必额外下载gradle。但由于国内网络下载gradle的jar实现太慢,因此我们需要给gradle加个速,相关配置如下:
在个人home目录下,创建.gradle文件夹,然后创建init.gradle文件:
$ cd ~
$ mkdir .gradle
$ cd .gradle
$ touch init.gradle
在init.gradle中添加如下内容:
allprojects {
repositories {
maven {
url "https://maven.aliyun.com/repository/public"
}
maven {
url "https://maven.aliyun.com/repository/jcenter"
}
maven {
url "https://maven.aliyun.com/repository/spring"
}
maven {
url "https://maven.aliyun.com/repository/spring-plugin"
}
maven {
url "https://maven.aliyun.com/repository/gradle-plugin"
}
maven {
url "https://maven.aliyun.com/repository/google"
}
maven {
url "https://maven.aliyun.com/repository/grails-core"
}
maven {
url "https://maven.aliyun.com/repository/apache-snapshots"
}
}
}
2.2 配置idea中的gradle
使用idea编译时,使用的是idea中的gradle,因此我们也需要配置下idea中的gradle,本人的配置如下:
gradle user home
默认是/home/你的用户名/.gradle
,如果修改了此目录,那么需要在新目录下添加一份init.gradle
文件
2.3 使用idea编译
首先获取spring代码,除了可以在命令行中使用命令git clone
外,也可以在idea中导入,方式如下:
当代码下载完成后,idea会自动进行编译操作。当然,我们也可手动运行idea的编译,方法如下:
点击build后,耐心等待即可。
还是那句话,初次构建,下载的依赖会很多,构建的时长取决于你的网速。
3. 其他
3.1 spring 5.2.2.RELEASE使用的gradle版本
查看spring使用的gradle版本,可以在spring项目下的gradle/wrapper/gradle-wrapper.properties
中查看:
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-5.6.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
从distributionUrl=https://services.gradle.org/distributions/gradle-5.6.4-bin.zip
可以知道,使用的是gradle版本为5.6.4
3.2 gradle版本过高导致编译出错
如果本地装了gradle且直接使用命令gradle build
(注意不是./gradlew build
)构建,可以会报 如下错误:
$ gradle build
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details
FAILURE: Build failed with an exception.
* Where:
Build file '/data/git_repository/spring-framework/build.gradle' line: 15
* What went wrong:
An exception occurred applying plugin request [id: 'com.gradle.build-scan', version: '2.4.2']
> Failed to apply plugin 'com.gradle.build-scan'.
> The build scan plugin is not compatible with this version of Gradle.
Please see https://gradle.com/help/gradle-6-build-scan-plugin for more information.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 9s
原因是gradle版本太高了,参考官网[4]说明。
解决方法也简单,可以降低gradle版本,要么升级插件版本,或者使用命令./gradlew build
。
4. 失败的尝试:使用maven本地仓库
在maven
与gradle
共存的情况下,有个尴尬的问题:同一个jar包,使用gradle构建时,会下载一份到gradle本地仓库中,使用maven构建时,也会下载一份到maven本的仓库。那么,有没有可能,让gradle使用maven本地仓库,从而同样一个jar包,在本地只保留一份jar包?对照着网上的文章,本人作了多次尝试,但都以失败告终,以下是本人的尝试过程。
4.1 添加环境变量GRADLE_USER_HOME
在环境变量中添加如下内容:
export GRADLE_USER_HOME=你的maven本地仓库地址
注意:这个配置仅对命令行构建生效,如果使用idea构建,还需要进行另外配置:
4.2 在$GRADLE_USER_HOME
目录下添加init.gradle
文件
allprojects {
repositories {
maven {
url "https://maven.aliyun.com/repository/public"
}
maven {
url "https://maven.aliyun.com/repository/jcenter"
}
maven {
url "https://maven.aliyun.com/repository/spring"
}
maven {
url "https://maven.aliyun.com/repository/spring-plugin"
}
maven {
url "https://maven.aliyun.com/repository/gradle-plugin"
}
maven {
url "https://maven.aliyun.com/repository/google"
}
maven {
url "https://maven.aliyun.com/repository/grails-core"
}
maven {
url "https://maven.aliyun.com/repository/apache-snapshots"
}
}
}
4.3 在gradle使用本地仓库
在spring-framework
的build.gradle
中进行maven本地仓库配置,具体为:
configure(allprojects) { project ->
apply plugin: "io.spring.dependency-management"
dependencyManagement {
...
repositories {
// 大约在294行,添加 mavenLocal(),表示使用maven本地仓库
mavenLocal()
mavenCentral()
maven { url "https://repo.spring.io/libs-spring-framework-build" }
}
...
}
...
}
4.4 进行编译,结果并没有达到预期
经过以上配置后,进行源码编译,发现会在maven的本地仓库下生成两个目录:
-
wrapper内容如下:
wrapper
└── dists
└── gradle-5.6.4-bin
└── bxirm19lnfz6nurbatndyydux
├── gradle-5.6.4
├── gradle-5.6.4-bin.zip
├── gradle-5.6.4-bin.zip.lck
└── gradle-5.6.4-bin.zip.ok
从内容可以知道,该目录用来存放编译过程中下载的gradle版本。
-
caches内容如下:
caches
├── 5.6.4
├── 6.6
├── build-cache-1
├── journal-1
├── modules-2
├── transforms-2
├── user-id.txt
└── user-id.txt.lock
该目录用来存放gradle构建过程中产生的缓存文件,这里我们主要关注modules-2
这个目录。稍微了解gradle的用户就知道,caches/modules-2/files-2.1
正是gradle用来存放jar包的地方,部分内容如下:
├── antlr
├── aopalliance
├── cglib
├── ch.qos.logback
├── com.beust
├── com.caucho
├── com.fasterxml
├── com.fasterxml.jackson
...
可以看到,jar包还是下载了,并没有使用maven本地仓库的jar包,以org.slf4j:slf4j-api
为例,maven本地仓库:
$ tree ~/.m2/repository/org/slf4j/slf4j-api/
/root/.m2/repository/org/slf4j/slf4j-api/
├── 1.7.25
│ ├── _remote.repositories
│ ├── slf4j-api-1.7.25.jar
│ ├── slf4j-api-1.7.25.jar.lastUpdated
│ ├── slf4j-api-1.7.25.jar.sha1
│ ├── slf4j-api-1.7.25.pom
│ └── slf4j-api-1.7.25.pom.sha1
└── 1.7.29
├── _remote.repositories
├── slf4j-api-1.7.29.jar
├── slf4j-api-1.7.29.jar.sha1
├── slf4j-api-1.7.29.pom
└── slf4j-api-1.7.29.pom.sha1
gradle本地仓库:
$ tree ~/.m2/repository/caches/modules-2/files-2.1/org.slf4j/slf4j-api/
~/.m2/repository/caches/modules-2/files-2.1/org.slf4j/slf4j-api/
├── 1.7.26
│ ├── 4d3419a58d77c07f49185aaa556a787d50508d27
│ │ └── slf4j-api-1.7.26.pom
│ └── 77100a62c2e6f04b53977b9f541044d7d722693d
│ └── slf4j-api-1.7.26.jar
└── 1.7.29
├── e56bf4473a4c6b71c7dd397a833dce86d1993d9d
│ └── slf4j-api-1.7.29.jar
└── f6bb48229ddfeb20486473b19b13fd9b72bbdb23
└── slf4j-api-1.7.29.pom
可以看到,相同的jar包slf4j-api-1.7.29.jar
,maven与gradle仓库各有一份,gradle并没有使用maven的本地仓库。
为了配置让两者使用同一仓库,本人在网上阅读了大量博客,配置方式大同小异,其中发现一篇博客遇到了与我同样的问题:Gradle 使用Maven的本地仓库(坑)[5],将博客中关于失败的内容摘录如下:
文中说,使用maven本地仓库的意思是,当发现maven本地仓库有该jar包,就从本地仓库复制到自己的仓库中,并不是复用maven的本地仓库。这与我尝试的结果大体一致。如果有小伙伴成功让gradle复用了maven的本地仓库,麻烦在留言指导下,在这里先谢过了。
5. 总结
本文介绍了如何编译spring源码,分别讲述了命令行和idea中如何编译,首次编译耗时会比较久,需要耐心等待下,问题不大。
源码编译完成了,接下来正式开启spring的源码分析之路!
本文原文链接:https://my.oschina.net/funcy/blog/4527453 ,限于作者个人水平,文中难免有错误之处,欢迎指正!原创不易,商业转载请联系作者获得授权,非商业转载请注明出处。
本系列的其他文章
【spring源码分析】spring源码分析系列目录
参考资料
获取spring源码: https://my.oschina.net/funcy/blog/4523714
[2]Build-from-Source: https://github.com/spring-projects/spring-framework/wiki/Build-from-Source
[3]import-into-idea: https://github.com/spring-projects/spring-framework/blob/master/import-into-idea.md
[4]这里: https://docs.gradle.com/enterprise/compatibility/#build_scan_plugin
[5]Gradle 使用Maven的本地仓库(坑): http://www.jeepxie.net/article/563412.html
以上是关于02. spring源码编译的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段