目录
前言:工欲善其事,必先利其器
目前还在摸索spring源码阅读,但是深有体会,阅读源码要一边看博客、书籍资料,一边debug源码,有些自己疑惑,但资料没解释清楚的,就要靠运行demo,debug源码理解了。
看了《spring源码深度解析》的spring环境搭建,也搜了很多博客,但是千人千面吧,会遇到别人没遇到的问题,或者别人的方式不适用,特此记录,仅供参考(ps:我的硬件环境是mac)。
tips:解决了"五-1-(4)-问题②"后,我意识到:gradle版本会影响环境搭建,最好使用源码指定的gradle版本,比如5.1.x spring指定gradle-4.10.3:
一、下载源码
方式1 - github
通过github的spring-framework项目地址:GitHub - spring-projects/spring-framework: Spring Framework
如果github无法访问,参考:Mac 无法访问github - 简书
方式2 - gitee码云
github拉取(或下载)代码太慢了!!!解决方案参考:解决Github代码拉取速度缓慢问题
总结:先用gitee从github拉取代码,再通过gitee下载或clone
二、准备gradle
我用的是gradle-4.4.1-all.zip搭建
1. 下载
传送门:Gradle | Releases,下载有点慢
2. 解压文件
放在这个目录下:/Users/你的用户名/.gradle/wrapper/dists
ps:尝试过放在其它自定义目录,但是通过idea导入工程的时候会报错
三、导入源码
我的IDEA版本是2018.3.6
ImportProject => 选择gradle => 指定gradle目录、其它选项 => finish
第1步 | 第2步 | 第3步 |
![]() | ![]() | ![]() |
四、编译准备
import项目,idea会自动尝试构建build,也可以手动触发
1. 解决问题
错误①:No such property: immutableValues for class: org.gradle.api.internal.tasks.DefaultTaskDependency
错误发生的位置:spring-beans项目 => spring-beans.gradle文件 => 最后几行
搜了很多博客,都是建议注释掉29、30两行,暂且照做,会给后期埋坑。心急看解决方案的可以直接看:"五-1-(4)-问题②"
错误②:Could not find method useJUnitPlatform() for arguments [spring_test_edty6ooeo2ucmkfu517bbq0z7$_run_closure4$_closure14@1eef8099] on task ':spring-test:junitJupiter' of type org.gradle.api.tasks.testing.Test.
错误发生位置:
遵从大众方案:注释掉101~104行
2. 手动build
可以看到idea在唰~~唰~~地下载jar包。玩了会手机后再看,还在下载,甚至会timeout中断下载(内心。。。。)
解决方案:增加阿里云镜像仓库!!在project的build.gradle文件的2处增加如下配置:
maven{ url 'https://maven.aliyun.com/nexus/content/groups/public/' }
maven{ url 'https://maven.aliyun.com/nexus/content/repositories/jcenter'}
![]() | ![]() |
新增仓库后,再手动build。等待一会,可以看到如下图,build成功了😊,spring模块都有蓝色方块了。如果build的过程还报一些非代码问题,就再手动build两次试试。
继续踩坑之旅。。。。。
五、创建自测的gradle项目
1. 普通Java项目
(1)新建
右键 => new => module => 选择gradle、选择java => next => 填入artifactId => next => finish。又是一阵自动build,还是成功的😊
![]() | ![]() |
(2)引入依赖
比如spring-aop模块引用了spring-core模块、spring-beans模块(提供ioc功能),可以通过spring-aop.gradle看到是如何引用的。
咱们有样学样,也粘贴这两行,毕竟阅读spring源码第一步就是阅读IOC,引入依赖:
(3)写demo
具体就不展开了,包括spring配置文件、bean、单测,主要是为了看getBean执行逻辑:
运行单测,迎接新坑出现。。。。。
(4)解决问题
问题①:cglib相关不存在
打开idea侧面的Gradle工具,找到spring-core => other => 双击cglibRepackJar即可,顺便双击objenesisRepackJar吧,因为待会就是报错找不到它😹
双击完上面两个后,单测顺利运行了!
问题②:有时候还会遇到报错:Circular dependency between the following tasks(如果没遇到,手动双击spring-beans的build试试😏)
对于Circular dependency问题,搜到有些博客是让我恢复之前注释的内容(见4-(1)-错误①),比如:编译spring源码Circular dependency between the following tasks - ymgydx的个人空间 - OSCHINA - 中文开源技术交流社区。恢复之后,又会报错:No such property: immutableValues for class: org.gradle.api.internal.tasks.DefaultTaskDependency(😹😹这不是死循环吗??)
解决方案:我琢磨no such property,那这个类有啥property呢,顺着包路径瞅到一个values属性,如下图:
抱着试试看的心态,做了如下修改:
def deps = compileGroovy.taskDependencies.immutableValues + compileGroovy.taskDependencies.mutableValues
改成:
def deps = compileGroovy.taskDependencies.values
然后,就顺利build了😊。接下来就可以自由发挥,写ioc、aop的测试demo了。
2. springmvc项目
这里的配置主要参考了2篇博客:
IntelliJ IDEA配置Web项目 - 简书:解释了IDEA的Facets、Artifacts,讲得很好
Spring源码——SpringMVC测试工程搭建_spring源码测试springmvc_等一杯咖啡的博客-CSDN博客:基于源码搭建springmvc工程
(1)新建
右键 => new => module => 选择gradle、选择java、选择Web => next => 填入artifactId => next => finish
![]() | ![]() |
(2)引入依赖
compile(project(":spring-web"))
compile(project(":spring-webmvc"))
(3)完善目录结构
我从其它springmvc项目中拷贝了WEB-INF目录及其子目录:
目前的目录结构 | 期望的目录结构 |
![]() | ![]() |
(4)项目配置
第1步:project structure配置 => 新建Facets | 第2步:选择spring-mywebtest_main模块 => ok | 第3步:地址调整 |
![]() | ![]() | Path: 修改前:/.../spring-framework/.idea/modules/spring-mywebtest/web/WEB-INF/web.xml 修改后:/.../spring-framework/spring-mywebtest/src/main/webapp/WEB-INF/web.xml Web Resource Directory: 修改前:/.../spring-framework/.idea/modules/spring-mywebtest/web 修改后:/.../spring-framework/spring-mywebtest/src/main/webapp |
第5步:将依赖的springwebmvc、springweb源码、配置文件一起打包,这里再给“等一杯咖啡”博主点赞(原文)。如果不打包,直接配置tomcat运行会报错:
One or more listeners failed to start. Full details will be found in the appropriate container log file
实际就是找不到spring-web中的ContextLoaderListener类,虽然自己明白问题在哪,之前不知道如何打包其它spring项目。
第4步:新建artifacts | 第5.1步:打包spring-webmvc_main、spring-web_main源码 | 第5.2步:打包spring-webmvc_main、spring-web_main的配置 |
![]() | ![]() |
②选择Module Sources |
第5.3步:打包spring-mywebtest项目自己的资源文件夹(同5.2相似):①选中classes;②选择Directory Content;③选择spring-mywebtest项目的resources文件夹
打包结果如下:
最后配置tomcat启动即可。
(5)引入其它spring模块的问题
dispatchServlet.xml中引入其它spring模块的标签,比如使用context:annotation-config、context:component-scan标签:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config />
<context:component-scan base-package="com.webtest"/>
...
</beans>
spring-mywebtest启动时会报错:
信息: Initializing Spring DispatcherServlet 'dispatcher'
ERROR DispatcherServlet Context initialization failed
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/context]
Offending resource: ServletContext resource [/WEB-INF/dispatcher-servlet.xml]
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:72)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:119)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:111)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.error(BeanDefinitionParserDelegate.java:281)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1388)
意思是无法定位到http://www.springframework.org/schema/context对应的spring-context.xsd的解析器。
实际工程应用中引入spring各模块的依赖,每个spring模块的resources文件夹中的配置文件都在类路径的jar包中,不会遇到问题。
而基于spring源码搭建的项目,虽然引入了spring-mvc模块,间接引入spring-context等模块,但没有将其它模块打包,因此项目文件中只保留了spring-mvc模块的spring.handlers、spring.schemas文件,如下图:
我没找到办法将spring-context等模块打包到lib目录中,但是想到其它有效的旁门左道:将spring-context模块中spring.handlers、spring.schemas文件的内容复制粘贴到spring-mvc模块的对应文件中,项目就可以启动了。