欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring源码(Gradle管理)转Maven项目

程序员文章站 2022-02-08 07:26:39
...

Spring源码(Gradle管理)转Maven项目

背景:项目源码是3.2.x,gradle4.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-publishuploadArchives, 网上也是查了好多,都搞不定,真实醉了,官方文档也只是介绍了单一模块的情况,真的快绝望了,最后发现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-repackspring-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构建成功了,真是不容易啊;

总结一下:解决问题的方法,首选官方文档:不过这次基本嗝屁,官方文档真的不是一般差劲啊;其次就是*这次也不行,最后一个很重要的就是源码中有单测或者样例这是非常重要的材料,切不可漫无目的的搜索了;

相关标签: Spring