Maven插件打fatjar的一些技巧

news2024/11/16 22:37:35

前言

最近做项目,Java实际上一般情况也不用fatjar,毕竟CICD都是流水线构建,不过在预研的过程中,使用fatjar可以内置manifest的main类直接启动,就很方便,尤其是在服务器运行环境。实际上golang还是很方便的,可以交叉编译二进制可执行文件,不过在交叉编译跨语言的能力的时候经常很难弄环境。

fatjar

先构建一个java命令可执行的jar,可执行jar实际上就是fatjar,只不过没有内置依赖,内置依赖有2种主流方式:1、class文件内置;2、自定义内置class和jar(springboot)。

构建一个最简单的demo,那么怎么让这个main被java指令执行,就需要构建manifest文件,相当于jdk的元数据

java可以直接执行class文件,这里使用jar,一般而言项目不可能是是没有任何依赖的,而且依赖也不好管理,所以SpringBoot的单个jar都很大,因为包括依赖jar。

参考JDK官方文档:icon-default.png?t=N7T8https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html 

可执行jar

第1步加入

第2步加入main-class

 

 通过官方文档知道原理后,一般都是通过Maven插件来打包,所以Maven加入如下插件

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>
                                com.feng.fatjar.demo.FatJarMain
                            </mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

打包后, 执行java -jar fat-jar-1.0-SNAPSHOT.jar

fatjar 

刚刚把class打成jar,并且可执行,但是如果有其他依赖jar怎么办,那么经常是一个大的可执行jar包。比如

代码改为

 

打包就需要把依赖包打入fatjar,使用各种Maven插件:

assembly插件
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.1</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.feng.fatjar.demo.FatJarMain</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

打包后执行

 shade插件

同理一般使用shade插件,实际上很多Javaagent就是用的这个插件来打fatjar的,通过自定义classloader载入。

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.1.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.feng.fatjar.demo.FatJarMain</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

执行结果同理

查看fatjar

 

 还可以对包名修改,这个一般在Javaagent中经常使用,比如日志jar的包名

修改包名

比如修改包名

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.1.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.feng.fatjar.demo.FatJarMain</mainClass>
                                </transformer>
                            </transformers>
                            <relocations>
                                <relocation>
                                    <pattern>org.apache.commons.lang3</pattern>
                                    <shadedPattern>shade.org.apache.commons.lang3</shadedPattern>
                                </relocation>
                            </relocations>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

修改后会统一替换字节码 

字节码修改技术

 SF、DSA、RSA冲突

Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes

如果jar包带签名,那么在fatjar执行时签名是不对的,毕竟都不是原来的jar了,计算的hash肯定不对,所谓验签就是拿证书(公钥)解密hash,然后自己计算hash,比对是否被改动。

fatjar必须排除这些文件,不能用原来的文件验签,也可以自己加签,这个是没问题的,见官方解释

经签名的Jar包内包含了以下内容:https://www.cnblogs.com/jackofhearts/p/jar_signing.html

  • 原Jar包内的class文件和资源文件
  • 签名文件 META-INF/*.SF:这是一个文本文件,包含原Jar包内的class文件和资源文件的Hash
  • 签名block文件 META-INF/*.DSA:这是一个数据文件,包含签名者的 certificate 和数字签名。其中 certificate 包含了签名者的有关信息和 public key;数字签名是对 *.SF 文件内的 Hash 值使用 private key 加密得来

那么排除签名文件

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>3.1.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>com.feng.fatjar.demo.FatJarMain</mainClass>
                                </transformer>
                            </transformers>
                            <relocations>
                                <relocation>
                                    <pattern>org.apache.commons.lang3</pattern>
                                    <shadedPattern>shade.org.apache.commons.lang3</shadedPattern>
                                </relocation>
                            </relocations>
                            <filters>
                                <filter>
                                    <artifact>*:*</artifact>
                                    <excludes>
                                        <exclude>META-INF/*.SF</exclude>
                                        <exclude>META-INF/*.DSA</exclude>
                                        <exclude>META-INF/*.RSA</exclude>
                                    </excludes>
                                </filter>
                            </filters>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

springboot打包 

这个经常用,毕竟现在的Java项目大部分都是springboot项目,参考springboot官网:Spring Boot Maven Plugin Documentation

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.5</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

这个就是springboot自定义加载的,还对要加载的类jar做了索引,方便读取

总结

实际上工作中大部分Java项目都是通过这种jar方式来来执行的,当然也可以封装java class -cp xxx的方式执行,不过文件太分散,不便管理。虽然很多情况,我们没细究这个执行逻辑,实际上大部分是各种基础中间件封装,原理还是JDK的执行指令和加载manifest逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1574904.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

倒计时】2024年全国大学生英语竞赛(附ABCD类历年真题+答案解析+24押题卷

倒计时】2024年全国大学生英语竞赛&#xff08;附ABCD类历年真题答案解析24押题卷 全国大学生英语竞赛&#xff08;NECCS&#xff09;是我国目前规模较大、参与人数众多的全国性大学生英语综合能力竞赛&#xff0c;在我国大学英语教学改革不断发展和大学就业日趋严峻的形势下&a…

SpringCloud Alibaba Sentinel 规则持久化

一、前言 接下来是开展一系列的 SpringCloud 的学习之旅&#xff0c;从传统的模块之间调用&#xff0c;一步步的升级为 SpringCloud 模块之间的调用&#xff0c;此篇文章为第十七篇&#xff0c;即使用 Sentinel 实现规则持久化。 二、概述 从前面我们做的实验可知&#xff0c;…

Java实现二叉树(上)

1.树型结构 1.1树型结构的概念 树是一种 非线性 的数据结构&#xff0c;它是由 n &#xff08; n>0 &#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看 起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的 1.2树型结构的特点…

能强优品木业提供高层建筑模板施工方案

在现代城市化进程中,高层建筑的兴建成为了建筑行业的一大重点。与普通建筑相比,高层建筑模板施工方案的制定需更加严谨周密,确保工程质量和施工安全。作为专业的建筑模板生产厂家,贵港市能强优品木业有限公司凭借25年丰富经验,为高层建筑模板施工提供了优质高效的解决方案。 首…

【Java基础】面试题汇总

Java基础面试题1. JVM vs JDK vs JRE 2. 什么是字节码?采用字节码的好处是什么?3. 为什么说 Java 语言“编译与解释并存”&#xff1f;4. AOT 有什么优点&#xff1f;为什么不全部使用 AOT 呢&#xff1f;5. Java 和 C 的区别&#xff1f;6. Java 中的基本数据类型&#xff1…

炎症性肠病和原发性胆汁性胆管炎之间的共同遗传结构(文献)

Investigating shared genetic architecture between inflammatory bowel diseases and primary biliary cholangitis - ScienceDirect 炎症性肠病&#xff08;IBD&#xff09;是一组慢性免疫介导的胃肠道特发性炎症&#xff0c;有两种形式&#xff0c;包括克罗恩病&#xff0…

Vue使用高德地图

1.在高德平台注册账号 2.我的 > 管理管理中添加Key 3.安装依赖 npm i amap/amap-jsapi-loader --save 或 yarn add amap/amap-jsapi-loader --save 4.导入 AMapLoade import AMapLoader from amap/amap-jsapi-loader; 5.直接上代码&#xff0c;做好了注释&#xff08;初始…

163 Linux C++ 通讯架构实战17,本地套接字整理对比,IPC:pipe,fifo,mmap,信号,本地套

IPC&#xff1a; Linux环境下&#xff0c;进程地址空间相互独立&#xff0c;每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到&#xff0c;所以进程和进程之间不能相互访问&#xff0c;要交换数据必须通过内核&#xff0c;在内核中开辟一块缓冲…

【C语言】——指针八:指针运算笔试题解析

【C语言】——指针八&#xff1a;指针运算笔试题解析 一、题一二、题二三、题三四、题四五、题五六、题六七、题七 一、题一 //程序输出结果是什么 int main() {int a[5] { 1,2,3,4,5 };int* ptr (int*)(&a 1);printf("%d, %d", *(a 1), *(ptr - 1));return…

基于JAVA+SSM+微信小程序+MySql的图书捐赠管理系统设计与实现(前后端分类)

一、项目背景介绍&#xff1a; 在当今社会&#xff0c;图书捐赠是一种普遍而有益的行为&#xff0c;旨在促进阅读、教育和知识传播。图书捐赠可以帮助改善教育资源不足的地区、学校和社区的阅读环境&#xff0c;提供更多的学习机会和知识获取途径。随着互联网和移动技术的发展&…

Java 面试宝典:Redis 的线程模型是怎么样的?

大家好&#xff0c;我是大明哥&#xff0c;一个专注「死磕 Java」系列创作的硬核程序员。 本文已收录到我的技术网站&#xff1a;https://www.skjava.com。有全网最优质的系列文章、Java 全栈技术文档以及大厂完整面经 Redis 的线程模型其实是分两块的&#xff1a; Redis 6.0 …

PostgreSQL:所有支持的数据类型及建表语句实例

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff01; 一、引言 在当今这个数据驱动的时代&#xff0c;数据库已经成为了企业和个人不可或缺的工具。而在众多数据库产品中&#xff0c;PostgreSQL以其强大的功能和高度的可扩展性&#xff0c;受到了越来越多开发者的青睐。…

FreeRTOSFreeRTOS列表和列表项

FreeRTOS列表和列表项 今天继续跟着正点原子学习FreeRTOS列表和列表项的内容。列表和列表项这个知识点用到了C语言链表的知识点。所以必须对C语言中的链表这个数据结构才能更好的理解这部分内容。TIPS&#xff1a;正点原子这节课内容讲的特别好&#xff0c;强烈推荐&#xff1…

《QT实用小工具·十八》高亮发光按钮控件

1、概述 源码放在文章末尾 该项目实现了高亮发光按钮控件 可设置文本&#xff0c;居中显示。可设置文本颜色。可设置外边框渐变颜色。可设置里边框渐变颜色。可设置背景色。可直接调用内置的设置 绿色、红色、黄色、黑色、蓝色 等公有槽函数。可设置是否在容器中可移动&#…

2024 抖音欢笑中国年(二):AnnieX互动容器创新玩法解析

本文基于24年抖音春节活动业务背景&#xff0c;介绍了字节跨端容器AnnieX在游戏互动套件上的探索&#xff0c;致力于提升容器在游戏互动场景的优化能力。 业务背景 AnnieX作为字节一方游戏统一容器&#xff0c;服务字节内部电商、直播、UG等跨端场景业务。在字节一方游戏互动场…

YOLOv8模型剪枝实战:Network Slimming网络瘦身方法

课程链接&#xff1a;YOLOv8模型剪枝实战&#xff1a;Network Slimming网络瘦身方法_在线视频教程-CSDN程序员研修院 YOLOv8是一个当前非常流行的目标检测器&#xff0c;本课程使用Network Slimming&#xff08;网络瘦身&#xff09;剪枝方法对YOLOv8进行模型剪枝&#xff0c;…

springboot国际化多语言

1,新建国际化多语言文件 在resources目录下新建 messages.properties 其他语言的文件 编辑messages.properties文件,下方从text切换到Resource Bundle ,即可对照着编辑多语言文件 (如果没有找到Resource Bundle,先在settings->plugins中安装Resource Bundle Editor) 2,配…

学习 MongoDB:打开强大的数据库技术大门

一、基本概念 MongoDB 是一个基于分布式文件存储的文档数据库&#xff0c;由 C 语言编写。它旨在为 Web 应用提供可扩展的高性能数据存储解决方案。 相信MySQL我们非常的熟悉&#xff0c;那么MySQL的表结构与MongoDB的文档结构进行类比的话可能更好理解MongoDB。 MySQL的数据…

Spyder无法载入(load)或者闪退问题

在Anaconda prompt中直接输入spyder&#xff0c;报错如下 Traceback (most recent call last):File "C:\Users\user\.conda\envs\KB\Scripts\spyder-script.py", line 10, in sys.exit(main())File "C:\Users\user\.conda\envs\KB\lib\site-packages\spyder\a…

baseline SE SP YI是什么?

SE、SP和YI是评估分类模型性能时常用的几个统计指标&#xff0c;特别是在医学影像处理、疾病诊断等领域&#xff0c;这些指标帮助了解模型对于正负类样本的识别能力。 SE (Sensitivity)&#xff0c;也称为真正率&#xff08;True Positive Rate, TPR&#xff09;或召回率&#…