Gradle 打包依赖为 fatJar 添加源码上传到 Maven

2024-02-21 10:18

本文主要是介绍Gradle 打包依赖为 fatJar 添加源码上传到 Maven,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文记录内容:Gradle 编译,打 jar 包的时候如果遇到有依赖库只有本地 jar 包,不提供在线仓库依赖的时候,如何把所有依赖打包在一起,附带自己的源码一起上传到 maven 仓库

Gradle: 4.10
Java: 1.8

1. 合并本地依赖 jar 包,打包出 fatJar

1.1 首先贴一下项目结构


buildscript {ext {nexusConfig = ["repository"      : "https://repo.xxxx","uploaderName"    : "xxx","uploaderPassword": "xxxxxx","readerName"      : "xxx","readerPassword"  : "xxxxxx"]}dependencies {classpath "com.github.jengelman.gradle.plugins:shadow:4.0.4"}repositories {jcenter()}
}subprojects {apply plugin: 'java'sourceCompatibility = 1.8group 'com.xxxx.xxxxxx'repositories {jcenter()mavenCentral()flatDir { dirs 'libs' }maven {url nexusConfig.repositorycredentials {username nexusConfig.readerNamepassword nexusConfig.readerPassword}}}dependencies {testImplementation 'junit:junit:4.12'}
}

Project 配置文件


version '1.1.2'
description 'xiaomi push service'dependencies {implementation fileTree('libs')
}apply from: "../publish.gradle"
apply from: "../shadow.gradle"

如上, 这是一个使用小米推送的服务端业务封装库,小米只提供了本地 jar 包,需要打包在一起供其他项目依赖。

1.2 使用 Shadow 插件打 fatJar

插件地址

shadow.gradle 的内容


apply plugin: 'com.github.johnrengelman.shadow'shadowJar {// 完整名称为 baseName-version-classifier.jarbaseName = project.name// 默认为 '-all' 为 null 则去除该参数classifier = nullversion = project.version// 方法数超过 65535 会报错, 需要打开下面这个配置//zip64 = true// 去除和添加文件 META-INF// include '.... 文件'// exclude '... 文件'// 如果有 Main 函数, 如下配置启动类//manifest {//    attributes 'Main-Class': 'com.example.Main'//}
}sourcesJar.dependsOn(shadowJar)

1.3 Shadow 打包原理

打 fatJar 有好几种方式,Shadow 用的是第二种

  1. 解压所有 jar,重新压缩合并在一个 jar 中
  2. 不合并,只是把依赖 jar 移动到最终 jar 包的 lib 目录下,然后在 manifest 中把 class-path 指向这个地址,那么加载类时就能正确找到
  3. 嵌套 jars, SpringBoot Gradle plugin 在用,需要用它的启动器自定义 ClassLoader 来启动,会加入很多业务无关代码

优点

  • 结构和原理简单
  • 不会有无关代码

缺点

  • 类文件路径被改了, 因此如果有直接调用 Class 文件名字或路径进行类加载的代码,会报错

1.4 Shadow 实现

插件会创建 2 个 task, shadowJar 负责打包, uploadShadow 负责上传 Maven,核心代码就是下面这一段了

protected void configureShadowTask(Project project) {JavaPluginConvention convention = project.convention.getPlugin(JavaPluginConvention)ShadowJar shadow = project.tasks.create(SHADOW_JAR_TASK_NAME, ShadowJar)shadow.group = SHADOW_GROUPshadow.description = 'Create a combined JAR of project and runtime dependencies'shadow.conventionMapping.with {map('classifier') {'all'}}if (GradleVersion.current() >= GradleVersion.version("5.1")) {shadow.archiveClassifier.set("all")}shadow.manifest.inheritFrom project.tasks.jar.manifestshadow.doFirst {def files = project.configurations.findByName(ShadowBasePlugin.CONFIGURATION_NAME).filesif (files) {def libs = [project.tasks.jar.manifest.attributes.get('Class-Path')]libs.addAll files.collect { "${it.name}" }manifest.attributes 'Class-Path': libs.findAll { it }.join(' ')}}shadow.from(convention.sourceSets.main.output)shadow.configurations = [project.configurations.findByName('runtimeClasspath') ?project.configurations.runtimeClasspath : project.configurations.runtime]shadow.exclude('META-INF/INDEX.LIST', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'module-info.class')project.artifacts.add(ShadowBasePlugin.CONFIGURATION_NAME, shadow)configureShadowUpload()}private void configureShadowUpload() {configurationActionContainer.add(new Action<Project>() {void execute(Project project) {project.plugins.withType(MavenPlugin) {Upload upload = project.tasks.withType(Upload).findByName(SHADOW_UPLOAD_TASK)if (!upload) {return}upload.configuration = project.configurations.shadowMavenPom pom = upload.repositories.mavenDeployer.pompom.scopeMappings.mappings.remove(project.configurations.compile)pom.scopeMappings.mappings.remove(project.configurations.runtime)pom.scopeMappings.addMapping(MavenPlugin.RUNTIME_PRIORITY, project.configurations.shadow, Conf2ScopeMappingContainer.RUNTIME)}}})}

上面的代码就是配置 task 实现了 jar 包位置替换, 指定 Class-Path,移除多余文件,去除 Maven 中的打包任务替换为自己的然后上传

更多代码看 GitHub

2. 上传源码到 Maven

按照第一节的内容,已经完成了打包 fatJar 并上传 Maven 的操作,但我发现使用 uploadShadow 这个 Shadow 插件自带的 task 上传的 jar 包里,不带源码!不爽,看看能不能改进。

2.1 不使用 uploadShadow 任务,但调用 shadowJar 任务做打包

实现方案如上述标题,默认的 Maven 插件提供的 task 中会调用 jar 这个 task 进行打包,如果有指定源码,那么也会同步上传源码,uploadShadow 中把实现给替换了,但没有写入上传源码的操作,就算打出源码也不会上传,所以换种思路。


apply plugin: 'maven'task sourcesJar(type: Jar) {classifier = 'sources'from sourceSets.main.java.srcDirs
}artifacts {archives sourcesJar
}// 如果希望 gradle install,安装到. m2 本地仓库,参考下面的内容
install {repositories.mavenInstaller {pom.project {version project.versionartifactId project.namegroupId project.grouppackaging 'jar'description project.description}}
}uploadArchives {configuration = configurations.archivesrepositories {mavenDeployer {repository(url: nexusConfig.repository) {authentication(userName: nexusConfig.uploaderName,password: nexusConfig.uploaderPassword)}snapshotRepository(url: nexusConfig.repositorySnapshot) {authentication(userName: nexusConfig.snapshotName,password: nexusConfig.snapshotPassword)}pom.project {version project.versionartifactId project.namegroupId project.grouppackaging 'jar'description project.description}}}
}

上面这个 publish.gradle 是无 shadow 依赖的, 只是加入一个全局的 sourceJar 任务用来生成源码。

configurations.archives 是 uploadArchives 任务的默认实现,会上传源码,因此我们只要让 sourceJar 和 shadowJar 这 2 个任务都运行一遍就可以了。

只要 shadow.gradle 在 publish.gradle 之后加载,它就能拿到 publish.gradle 中定义的 sourceJar 任务,并指定这个任务依赖 shadowJar 运行,uploadArchives 在进行编译源码操作时会连带先调用 shadowJar 编译 fatJar 替换掉 jar 任务的编译结果,最后一起上传,简单并解耦的实现了打包 fatJar 并带源码上传 Maven 的需求

apply from: "../publish.gradle"
apply from: "../shadow.gradle"

shadow.gradle

apply plugin: 'com.github.johnrengelman.shadow'shadowJar {.....
}sourcesJar.dependsOn(shadowJar)

3. 相同需求用Maven怎么做

Maven就是xml丑了点,其实配置很简单


<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>3.2.0</version><executions><execution><goals><goal>shade</goal></goals><configuration><transformers><transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"><manifestEntries><Main-Class>${app.main.class}</Main-Class><X-Compile-Source-JDK>${maven.compile.source}</X-Compile-Source-JDK><X-Compile-Target-JDK>${maven.compile.target}</X-Compile-Target-JDK></manifestEntries></transformer></transformers></configuration></execution></executions></plugin><!-- 要将源码放上去,需要加入这个插件 --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-source-plugin</artifactId><configuration><attach>true</attach></configuration><executions><execution><!-- 将goal绑定到verify这个节点,可以避免每次compile代码时候都做打包源码 --><phase>verify</phase><goals><goal>jar</goal></goals></execution></executions></plugin></plugins></build>

替换${app.main.class}为你的main函数所在的类
${maven.compile.source}是你的项目源码的JDK版本如1.8
${maven.compile.target}是你的项目编译的Java版本如1.8

这篇关于Gradle 打包依赖为 fatJar 添加源码上传到 Maven的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/731432

相关文章

Spring AI Alibaba接入大模型时的依赖问题小结

《SpringAIAlibaba接入大模型时的依赖问题小结》文章介绍了如何在pom.xml文件中配置SpringAIAlibaba依赖,并提供了一个示例pom.xml文件,同时,建议将Maven仓... 目录(一)pom.XML文件:(二)application.yml配置文件(一)pom.xml文件:首

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

CentOS系统Maven安装教程分享

《CentOS系统Maven安装教程分享》本文介绍了如何在CentOS系统中安装Maven,并提供了一个简单的实际应用案例,安装Maven需要先安装Java和设置环境变量,Maven可以自动管理项目的... 目录准备工作下载并安装Maven常见问题及解决方法实际应用案例总结Maven是一个流行的项目管理工具

使用maven依赖详解

《使用maven依赖详解》本文主要介绍了Maven的基础知识,包括Maven的简介、仓库类型、常用命令、场景举例、指令总结、依赖范围、settings.xml说明等,同时,还详细讲解了Maven依赖的... 目录1. maven基础1.1 简介1.2 仓库类型1.3 常用命令1.4 场景举例1.5 指令总结

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

关于Maven生命周期相关命令演示

《关于Maven生命周期相关命令演示》Maven的生命周期分为Clean、Default和Site三个主要阶段,每个阶段包含多个关键步骤,如清理、编译、测试、打包等,通过执行相应的Maven命令,可以... 目录1. Maven 生命周期概述1.1 Clean Lifecycle1.2 Default Li

关于Maven中pom.xml文件配置详解

《关于Maven中pom.xml文件配置详解》pom.xml是Maven项目的核心配置文件,它描述了项目的结构、依赖关系、构建配置等信息,通过合理配置pom.xml,可以提高项目的可维护性和构建效率... 目录1. POM文件的基本结构1.1 项目基本信息2. 项目属性2.1 引用属性3. 项目依赖4. 构

Spring核心思想之浅谈IoC容器与依赖倒置(DI)

《Spring核心思想之浅谈IoC容器与依赖倒置(DI)》文章介绍了Spring的IoC和DI机制,以及MyBatis的动态代理,通过注解和反射,Spring能够自动管理对象的创建和依赖注入,而MyB... 目录一、控制反转 IoC二、依赖倒置 DI1. 详细概念2. Spring 中 DI 的实现原理三、

Python项目打包部署到服务器的实现

《Python项目打包部署到服务器的实现》本文主要介绍了PyCharm和Ubuntu服务器部署Python项目,包括打包、上传、安装和设置自启动服务的步骤,具有一定的参考价值,感兴趣的可以了解一下... 目录一、准备工作二、项目打包三、部署到服务器四、设置服务自启动一、准备工作开发环境:本文以PyChar