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

相关文章

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

一文教你如何将maven项目转成web项目

《一文教你如何将maven项目转成web项目》在软件开发过程中,有时我们需要将一个普通的Maven项目转换为Web项目,以便能够部署到Web容器中运行,本文将详细介绍如何通过简单的步骤完成这一转换过程... 目录准备工作步骤一:修改​​pom.XML​​1.1 添加​​packaging​​标签1.2 添加

Flutter打包APK的几种方式小结

《Flutter打包APK的几种方式小结》Flutter打包不同于RN,Flutter可以在AndroidStudio里编写Flutter代码并最终打包为APK,本篇主要阐述涉及到的几种打包方式,通... 目录前言1. android原生打包APK方式2. Flutter通过原生工程打包方式3. Futte

Spring 中 BeanFactoryPostProcessor 的作用和示例源码分析

《Spring中BeanFactoryPostProcessor的作用和示例源码分析》Spring的BeanFactoryPostProcessor是容器初始化的扩展接口,允许在Bean实例化前... 目录一、概览1. 核心定位2. 核心功能详解3. 关键特性二、Spring 内置的 BeanFactory

Maven pom.xml文件中build,plugin标签的使用小结

《Mavenpom.xml文件中build,plugin标签的使用小结》本文主要介绍了Mavenpom.xml文件中build,plugin标签的使用小结,文中通过示例代码介绍的非常详细,对大家的学... 目录<build> 标签Plugins插件<build> 标签<build> 标签是 pom.XML

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

IDEA与JDK、Maven安装配置完整步骤解析

《IDEA与JDK、Maven安装配置完整步骤解析》:本文主要介绍如何安装和配置IDE(IntelliJIDEA),包括IDE的安装步骤、JDK的下载与配置、Maven的安装与配置,以及如何在I... 目录1. IDE安装步骤2.配置操作步骤3. JDK配置下载JDK配置JDK环境变量4. Maven配置下

Python如何快速下载依赖

《Python如何快速下载依赖》本文介绍了四种在Python中快速下载依赖的方法,包括使用国内镜像源、开启pip并发下载功能、使用pipreqs批量下载项目依赖以及使用conda管理依赖,通过这些方法... 目录python快速下载依赖1. 使用国内镜像源临时使用镜像源永久配置镜像源2. 使用 pip 的并

linux打包解压命令方式

《linux打包解压命令方式》文章介绍了Linux系统中常用的打包和解压命令,包括tar和zip,使用tar命令可以创建和解压tar格式的归档文件,使用zip命令可以创建和解压zip格式的压缩文件,每... 目录Lijavascriptnux 打包和解压命令打包命令解压命令总结linux 打包和解压命令打