Spring源码(Gradle管理)转Maven项目
Spring源码(Gradle管理)转Maven项目
背景:项目源码是3.2.x
,gradle
是4.10.2
。最开始首先就是替换maven*仓库为阿里云的*仓库,其实执行安装的时候一定要用./gradlew install
不要用原生的gradle install
会有各种问题;
一、添加maven插件
首先在build.gradle
脚本中添加maven插件
:
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'eclipse'
group = 'org.springframework'
version = '3.2.100-SNAPSHOT'
同时修改gradle.properties
的版本号为上述一致就行;此时在根目录运行./gradlew install
就会在各个模块下面build目录生成pom-default.xml
,现在还不能直接使用,另外打包有点慢,浪费生命,注释掉一些不必要的任务,如下所示:
artifacts {
//archives sourcesJar //打包源码
//archives javadocJar //打包文档
}
artifacts {
//archives docsZip //所有文档打包压缩
//archives schemaZip //schema压缩
//archives distZip //dist
}
二、添加拷贝任务
前面讲到在build目录下生成pom-default.xml
,但是因为不在模块根目录下,且名字不叫pom.xml
所以不能使用,需要拷贝到根目录下面。可以通过在configure(subprojects - project(":spring-build-src")) { subproject ->
下面新增copy任务,两种实现方案:
1、方案一
task copyPomXml(type: Copy, dependsOn: jar){
def fileExist = file("${subproject.buildDir}/poms/pom-default.xml").exists()
if (!fileExist) {
println("file ${subproject.buildDir}/poms/pom-default.xml not exist!")
}
println("from ${subproject.buildDir}/poms/pom-default.xml to ${subproject.projectDir}/pom.xml")
file("${subproject.buildDir}/poms/pom-default.xml").renameTo(file("${subproject.projectDir}/pom.xml"))
}
install.dependsOn(copyPomXml)
2、方案二
//必须等到jar生成以后才能执行拷贝,否则pom文件不存在
task copyPomXml2(type: Copy, dependsOn: jar){
//from,to里面一定要使用双引号,否则变量解析不了,
//而且也没有异常,使用debug模式会告诉你找不到源文件
from("${subproject.buildDir}/poms")
include '**/*.xml'
into file("${subproject.projectDir}/")
rename { filename ->
filename.replace 'pom-default', 'pom'
}
//允许拷贝空目录
includeEmptyDirs = true
}
//在最终install任务之前执行,install之前会有各种编译打包任务
install.dependsOn(copyPomXml2)
至此完成了根目录下pom文件的生成,真是不容易啊,弄了好久,遇到各种莫名其妙的问题,主要是很多异常打的莫名其妙,相对于java等语言,来讲,定位问题的成本真的很高;可是很多事情并没有那么圆满,这样生成的pom缺失一堆依赖项;后面研究使用maven-publish
插件参考;参考2
三、通过Gradle发布Jar到远程*仓库
期间因多次尝试转Maven工程失败,想过Gradle能够直接使用maven*仓库, 那是否也可以直接上传到maven仓库呢?通过检索有两种方式:maven-publish
和uploadArchives
, 网上也是查了好多,都搞不定,真实醉了,官方文档也只是介绍了单一模块的情况,真的快绝望了,最后发现Gradle的GitHub源码中有示例multiple-publications,按照这个例子,只要在build.gradle
最外层增加如下代码:
1、使用maven-publish
插件,分开配置
第一步:配置发布的*仓库地址/登入信息
subprojects {
apply plugin: 'java'
apply plugin: 'maven-publish'
repositories {
mavenCentral()
}
publishing {
repositories {
maven {
url "填上maven*仓库地址"
credentials {
username 'a'
password 'b'
}
}
}
}
}
第二步:配置发布artifact属性–分项目配置
然后在每个字项目中添加如下代码:下面以project("spring-core"){}
为例:
publishing {
publications {
maven(MavenPublication) {
groupId = 'org.springframework'
artifactId = 'spring-core'
version = '3.2.100-SNAPSHOT'
from components.java
}
}
}
2、使用maven-publish
插件,通用配置
前面提到的方法是要一个子项目一个子项目的配置,是在太麻烦,而且不通用,下面给出一种通用的配置。
第二步:配置发布artifact属性
第一步直接略过,和前面的一样,直接进入第二步,使用subprojects来进行配置。
subprojects {subproject ->
apply plugin: 'java'
apply plugin: 'maven-publish'
repositories {
mavenCentral()
}
publishing {
repositories {
maven {
url "maven*仓库地址"
credentials {
username 'a'
password 'b'
}
}
}
publications {
maven(MavenPublication) {
groupId = 'org.springframework'
artifactId = subproject.name
version = '3.2.100-SNAPSHOT'
from components.java
}
}
}
}
具体发布命令是:./gradlew publish
(./gradlew publish -debug
可以看异常)
3、使用uploadArchives
插件,通用配置
subprojects {subproject ->
apply plugin: "java"
apply plugin: "maven"
uploadArchives {
repositories {
mavenDeployer {
repository(url: "maven*仓库") {
authentication(userName: "a", password: "b")
}
pom.groupId == subproject.group
pom.artifactId == subproject.name
pom.version == subproject.version
}
}
}
}
4、使用maven
插件的pom
方法生成并移动pom.xml
前面提到了一种方法生成并移动pom.xml,但是不够官方,下面通过官方pom方法来实现。
第一步:项目根目录生成pom.xml文件
subprojects {subproject ->
apply plugin: "java"
apply plugin: "maven"
//uploadArchives部分省略
task writeNewPom {
doLast {
pom {
project {
inceptionYear '2008'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
}.writeTo("${subproject.projectDir}/pom.xml")
}
}
}
第二步:解决pom.xml中错误的scope问题
前面已经在在子项目目录下生成pom.xml文件的方式,但是最终使用spring-core
测试无效,原因是例如jopt-simple
虽然存在在xml中,但是其scope是 <scope>optional</scope>
,这是错误的,没有scope定义为optional;解决方法,在writeNewPom
中添加修改动作withXml:
task writeNewPom {
doLast {
pom {
project {
inceptionYear '2008'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
withXml {
asNode().dependencies.'*'.findAll() {
it.scope.text() == 'optional' &&
project.configurations.compile.allDependencies.find { dep ->
dep.name == it.artifactId.text()
}
}.each { it.scope*.value = 'compile'}
}
}.writeTo("${subproject.projectDir}/pom.xml")
}
}
第二步:解决pom.xml中缺失非标准scope依赖
所谓非标准scope依赖如下:
asm("org.ow2.asm:asm:${asmVersion}@jar")
asm("org.ow2.asm:asm-commons:${asmVersion}@jar")
cglib("cglib:cglib:${cglibVersion}@jar")
jarjar("com.googlecode.jarjar:jarjar:1.3")
为了解决这个问题,查了很多资料,最终找到DependencyReportTask有mvn dependency:tree
的功能,所以研究一下,写个task来修改pom就好了;方法就是使用configurations.all.each
来配置。先给出DependencyReportTask的使用样例。
//类似于mvn dependency:tree
task allDeps(type: DependencyReportTask) {}
allDeps.onlyIf {subproject.name == "spring-core"}
下面给出解决方案:
task doDependencies(dependsOn: writeNewPom) {
doLast {
def xmlRoot = new XmlParser().parse(file("${subproject.projectDir}/pom.xml"))
def depRoot = xmlRoot.dependencies
def depRootFirst = depRoot.first()
depRootFirst.dependency.each{dep ->
depRootFirst.remove(dep)
}
configurations.all.each { configuration ->
configuration.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def elem = artifact.moduleVersion.id
def dr = depRootFirst.appendNode("dependency")
dr.appendNode("groupId","${elem.group}")
dr.appendNode("artifactId","${elem.name}")
dr.appendNode("version","${elem.version}")
}
}
def printer = new XmlNodePrinter(new PrintWriter(new FileWriter("${subproject.projectDir}/pom.xml")))
printer.preserveWhitespace = true
printer.print(xmlRoot)
}
}
第三步:解决pom.xml中缺失本地jar包引用
走完上面一部之后,mvn还是报错,原因是找不到spring-asm-repack
和spring-cglib-repack
这两个包,查看源码发现这个包是通过本地引用jar包的方式来使用,而且还是通过其他包改名字得来的,下面先给出本地引用的代码
dependencies {
compile(files(cglibRepackJar))
compile(files(asmRepackJar))
}
在GitHub上面找到如下代码(通过搜索compile(files
):
println "file-dependencies: " + configurations.compile.files { it instanceof FileCollectionDependency }.collect { it.name }
分析得出下面方案进行分析文件依赖的方式:
task doDependencies(dependsOn: [writeNewPom, copyLocalJar]) {
if(subproject.name == "spring-core"){
dependsOn cglibRepackJar
}
doLast {
def xmlRoot = new XmlParser().parse(file("${subproject.projectDir}/pom.xml"))
def depRoot = xmlRoot.dependencies
def depRootFirst = depRoot.first()
//println(depRootFirst)
depRootFirst.dependency.each{dep ->
depRootFirst.remove(dep)
}
Map<String,String> map = new HashMap<String, String>()
configurations.all.each { configuration ->
configuration.resolvedConfiguration.resolvedArtifacts.each { artifact ->
def elem = artifact.moduleVersion.id
def key = "${elem.name}"
if(!map.containsKey(key)){
def dr = depRootFirst.appendNode("dependency")
dr.appendNode("groupId","${elem.group}")
dr.appendNode("artifactId","${elem.name}")
dr.appendNode("version","${elem.version}")
map.put(key, "1")
}
}
configuration.files { it instanceof FileCollectionDependency }.collect { it }.each { file ->
def key = "${file.name}"
def arr = file.name.split("-")
def sub = arr[0..arr.size()-2]
println(sub.toString())
String name = sub.join("-")
def version = arr[arr.size()-1].replace(".jar","")
if(!map.containsKey(key)){
def dr = depRootFirst.appendNode("dependency")
dr.appendNode("groupId","${subproject.group}")
dr.appendNode("artifactId","${name}")
dr.appendNode("version","${version}")
dr.appendNode("scope","system")
dr.appendNode("systemPath","${subproject.projectDir}/src/main/resources/lib/"+key)
map.put(key, "1")
}
}
}
def printer = new XmlNodePrinter(new PrintWriter(new FileWriter("${subproject.projectDir}/pom.xml")))
printer.preserveWhitespace = true
printer.print(xmlRoot)
}
}
}
dependsOn cglibRepackJar
值得关注,就是必须等文件依赖解析完成,且doDependencies
必须在 cglibRepackJar之后声明,这样运行./gradlew doDependencies
构建成功之后就产生了完整的pom文件。然后执行:
cd ./spring-core
mvn clean install -Dmaven.test.skip=true
终于看到maven构建成功了,真是不容易啊;
总结一下:解决问题的方法,首选官方文档:不过这次基本嗝屁,官方文档真的不是一般差劲啊;其次就是*这次也不行,最后一个很重要的就是源码中有单测或者样例这是非常重要的材料,切不可漫无目的的搜索了;
上一篇: 深度优先和广度优先的Python实现
下一篇: 图的深度优先查找,与深度优先查找