- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
有一天螃蟹出门,不小心撞倒了泥鳅 泥鳅很生气地说:你是不是瞎啊! 螃蟹说:不是啊,我是螃蟹 。
maven-shade-plugin 官网已经介绍的很详细了,我给大家简单翻译一下 。
This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. 。
这段话简明扼要的概述了 maven-shade-plugin 的功能 。
能够将项目连同其依赖,一并打包到一个 uber-jar 中 。
uber-jar 就是一个超级 jar,不仅包含我们的工程代码,还包括依赖的 jar,和 spring-boot-maven-plugin 类似 。
能够对依赖 jar 中的包名进行重命名 。
这个功能就有意思了,后面我们详说 。
maven-shade-plugin 必须和 Maven 构建生命周期的 package 阶段绑定,那么当 Maven 执行 mvn package 时会自动触发 maven-shade-plugin;使用很简单,在 pom.xml 添加该插件依赖即可 。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<!-- 和 maven package 阶段绑定 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!-- 按需自定义配置 -->
</configuration>
</execution>
</executions>
</plugin>
phase 和 goal 按如上固定配置,configuration 才是我们自由发挥的平台;有了基本了解后,我们再结合官方提供的 Examples 来看看 maven-shade-plugin 具体能干啥 。
假设我们有项目 maven-shade-plugin-demo,其项目结构如下 。
如果不做任何剔除,可以按如下配置进行全打包 。
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<!-- 和 package 阶段绑定 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!-- 按需自定义配置 -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
执行 mvn package 后,我们会看到两个包 。
maven-shade-plugin-demo-1.0-SNAPSHOT.jar 就是 uber-jar;解压可看其结构 。
不仅包括 package、还包括各种配置文件、元文件,统统打包进 uber-jar;而 original-maven-shade-plugin-demo-1.0-SNAPSHOT.jar 则是不包括依赖 jar 的原始项目包;如果我们比较细心的话,会发现打包的时候告警了 。
意思是说 hutool jar 包中有 META-INF/MANIFEST.MF,而 maven-shade-plugin-demo 打包成 jar 后也包含 META-INF/MANIFEST.MF,两者重复了,只会将其中一个复制进 uber jar;默认情况下,是将我们项目的 jar 中的 META-INF/MANIFEST.MF 复制进 uber jar 。
那如果我们想保留 hutool 下的 MANIFEST.MF,而去掉 maven-shade-plugin-demo 中的 MANIFEST.MF,该如何处理呢?只需要微调下 configuration 。
<configuration>
<filters>
<filter>
<artifact>com.qsl:maven-shade-plugin-demo</artifact>
<excludes>
<exclude>META-INF/*.MF</exclude>
</excludes>
</filter>
</filters>
</configuration>
此时 uber jar 中的 MANIFEST.MF 就来自 hutool jar 了 。
回到前面的 configuration 配置,我们需要明白其每个子标签的含义 。
filter:过滤器,可以配置多个 。
artifact:复合标识符,用来匹配 jar,简单点说,就是匹配 jar 的 匹配规则 。
按 Maven 的坐标:groupId:artifactId[[:type]:classifier] 进行配置,groupId:artifactId 必配,[[:type]:classifier] 选配;支持通配符 * 和 ?,例如:<artifact>*:*</artifact>(相当于匹配上所有jar) 。
exclude:排除项,也就是不会复制进 uber-jar;支持通配符配置 。
include:包含项,也就是只有这些会被复制进 uber-jar;支持通配符配置 。
我们实战下,假设我们项目结构如下所示 。
configuration 配置如下 。
<configuration>
<filters>
<filter>
<artifact>com.qsl:maven-shade-plugin-demo</artifact>
<excludes>
<exclude>com/qsl/test/**</exclude>
<exclude>com/qsl/Entry.class</exclude>
</excludes>
</filter>
<filter>
<artifact>cn.hutool:hutool-all</artifact>
<includes>
<include>cn/hutool/Hutool.class</include>
<include>cn/hutool/json/**</include>
</includes>
</filter>
</filters>
</configuration>
执行 mvn package 后,uber-jar 内部结构你们能想到吗?我们来看看实际结果 。
是不是和跟你们想的一样?
除了手动指定 filter 外,此插件还支持自动移除项目中没有使用到的依赖类,以此来最小化 uber jar 的体积;configuration 配置如下 。
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
我们在 StringUtil 中引入 hutool 的 StrUtil(相当于项目依赖了 StrUtil) 。
package com.qsl.util;
import cn.hutool.core.util.StrUtil;
/**
* @author: 青石路
*/
public class StringUtil {
public static boolean isBlank(String str) {
return StrUtil.isBlank(str);
}
}
然后打包,uber-jar 内部结构如下所示 。
从 maven-shade-plugin 1.6 开始,minimizeJar 会保留 filter 中 include 配置的类,但是要注意:
inlcude 默认会排除所有不在 include 配置中的类 。
这就会导致问题,我们来看个案例,我们引入 logback 依赖,但代码中未用到它,而我们又想将其下的 class 复制进 uber-jar,另外我们还想将 hutool 的 cn/hutool/json 包下的全部类都复制进 uber-jar,并且开启 minimizeJar,是不是按如下配置?
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.14</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<!-- 和 package 阶段绑定 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>ch.qos.logback:logback-classic</artifact>
<includes>
<include>**</include>
</includes>
</filter>
<filter>
<artifact>cn.hutool:hutool-all</artifact>
<includes>
<include>cn/hutool/json/**</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
打包后看 uber-jar 目录结构 。
hutool 的 core 包没有复制进来,这是因为我们对 hutool 配置了 include ,默认把最小依赖的 core 包给排除掉了,那怎么办呢?插件提供了配置 <excludeDefaults>false</excludeDefaults> 来处理此种情况,它会覆盖 include 默认排除行为 。
<filter>
<artifact>cn.hutool:hutool-all</artifact>
<excludeDefaults>false</excludeDefaults>
<includes>
<include>cn/hutool/json/**</include>
</includes>
</filter>
这样配置之后,既能包含 hutool 的 json 包,又能包含最小依赖的 core 包 。
false 通常配合 true 来使用,不然 。
<configuration> <filters> <filter> <artifact>cn.hutool:hutool-all</artifact> <excludeDefaults>false</excludeDefaults> <includes> <include>cn/hutool/json/**</include> </includes> </filter> </filters> </configuration>
这么配置有何意义?
如果 uber-jar 被其他项目依赖,而我们的 uber-jar 又是保留了依赖 jar 的 class 的全类名,那么就可能类重复而导致类加载冲突;比如项目A依赖了我们的 maven-shade-plugin-demo,还依赖了 B.jar,两个 jar 中都存在 cn.hutool.core.util.StrUtil.class,但 api 完全不一样,根据 双亲委派模型,只会成功加载其中某个 cn.hutool.core.util.StrUtil.class,那么另一个的 api 则使用不了。为了解决这个问题,插件提供了重定位功能,通过创建 class 字节码的私有副本,按新配置的 package,打包进 uber-jar 。
我们来看个案例,假设我们只需要 hutool 的 core 包,将其下所有的 class 按 com.qsl.core 包打包进 uber-jar,可以按如下配置 。
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.26</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<!-- 和 package 阶段绑定 -->
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>cn.hutool.core</pattern>
<shadedPattern>com.qsl.core</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>cn.hutool:hutool-all</artifact>
<includes>
<include>cn/hutool/core/**</include>
</includes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
打包后 uber-jar 目录结构如下 。
我们来看下 uber-jar 中的 StringUtil.class 。
依赖的 StrUtil 也被正确调整了,是不是很牛皮?
此时项目A 依赖 B.jar 的同时,又依赖我们的 maven-shade-plugin-demo,就不会类重名了(package 不一致了) 。
relocation 同样支持 exclude 和 include 。
<configuration>
<relocations>
<relocation>
<pattern>cn.hutool.core</pattern>
<shadedPattern>com.qsl.core</shadedPattern>
<!-- exclude 指定的不重定向,其他重定向 -->
<excludes>
<exclude>cn.hutool.core.util.ObjUtil</exclude>
<!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
<exclude>cn.hutool.core.date.**</exclude>
</excludes>
</relocation>
<relocation>
<pattern>cn.hutool.json</pattern>
<shadedPattern>com.qsl.json</shadedPattern>
<!-- include 指定的重定向,其他不重定向 -->
<includes>
<include>cn.hutool.json.JSONUtil</include>
<!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
<include>cn.hutool.json.xml.**</include>
</includes>
</relocation>
</relocations>
<filters>
<filter>
<artifact>cn.hutool:hutool-all</artifact>
<includes>
<include>cn/hutool/core/**</include>
<include>cn/hutool/json/**</include>
</includes>
</filter>
</filters>
</configuration>
此时 uber-jar 的目录结构是怎样的?你们自己去试! 。
前面已经介绍过,打包后会生成两个包 。
但 original 开头的那个明显不是按 Maven 坐标命名的,所以它是不能够 install 到本地或者远程仓库的;如果需要将两个 jar 都 install 到仓库中,那么就需要用到插件的 Attaching the Shaded Artifact (生成附属包)功能 。
<configuration>
<relocations>
<relocation>
<pattern>cn.hutool.core</pattern>
<shadedPattern>com.qsl.core</shadedPattern>
<!-- exclude 指定的不重定向,其他重定向 -->
<excludes>
<exclude>cn.hutool.core.util.ObjUtil</exclude>
<!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
<exclude>cn.hutool.core.date.**</exclude>
</excludes>
</relocation>
<relocation>
<pattern>cn.hutool.json</pattern>
<shadedPattern>com.qsl.json</shadedPattern>
<!-- include 指定的重定向,其他不重定向 -->
<includes>
<include>cn.hutool.json.JSONUtil</include>
<!-- 一个*只会过滤包下的class,两个*会过滤包下的class和子包 -->
<include>cn.hutool.json.xml.**</include>
</includes>
</relocation>
</relocations>
<filters>
<filter>
<artifact>cn.hutool:hutool-all</artifact>
<includes>
<include>cn/hutool/core/**</include>
<include>cn/hutool/json/**</include>
</includes>
</filter>
</filters>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>qsl</shadedClassifierName>
</configuration>
部署到仓库的 jar 如下 。
这个就比较简单了,我们直接看配置 。
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.qsl.Entry</mainClass>
</transformer>
</transformers>
</configuration>
如上配置会将 Main-Class 写进 uber-jar 的 MANIFEST.MF,还可以通过 manifestEntries 自定义属性 。
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<mainClass>com.qsl.Entry</mainClass>
<Build-Author>qsl</Build-Author>
</manifestEntries>
</transformer>
</transformers>
</configuration>
打包之后,uber-jar 的 MANIFEST.MF 内容如下 。
Resource Transformers 已经介绍的很详细了,我就不一一介绍了,挑几个个人认为比较重要的简单讲一下 。
合并 META-INF/services/ 下的文件,并对文件中的 class 进行重定向;我们来看个例子,hutool 下有文件 cn.hutool.aop.proxy.ProxyFactory 。
我们也自定义一个 。
configuration 配置如下 。
<configuration>
<relocations>
<relocation>
<pattern>cn.hutool.aop</pattern>
<shadedPattern>com.qsl.aop</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
打包后,hutool 与 uber-jar 的 cn.hutool.aop.proxy.ProxyFactory 文件内容差异如下 。
如果不配置 ServicesResourceTransformer,结果是怎样,你们自己去试 。
将多个同名文件的内容合并追加到一起(不配置的情况下会覆盖,最终文件内容只是其中某个文件的内容),configuration 配置如下 。
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
</transformers>
</configuration>
打包后文件内容合并如下 。
XmlAppendingTransformer、ResourceBundleAppendingTransformer 功能类似,只是针对的文件内容格式略微有点特殊,就不演示了,你们自行去测试 。
回到我们的主题,如果我们项目依赖的 jar 中出现了同名的 class (包名和类名均相同),根据 双亲委派模型,只会加载其中某一个 class,虽然两个 class 同名了,但功能完全不一样,另一个未被加载的 class 的功能则用不了,如果想同时使用这两个同名 class 的功能,我们该如何处理?
甲方扔给两个存在包名与类名均相同的Jar包,要在工程中同时使用怎么办?
文中给出了几种解决方案(注意看评论区),最高效最实用的当属 maven-shade-plugin;假设我们项目依赖的 A.jar 和 B.jar 都存在 com.qsl.Hello.class,我们可以新建一个项目,名字叫 qsl-a,没有任何代码,仅仅依赖 A.jar,然后利用 maven-shade-plugin 的 Relocating Classes 功能对 A.jar 中存在重名的 class 进行重定向,例如 。
<configuration>
<relocations>
<relocation>
<pattern>com.qsl</pattern>
<shadedPattern>com.qsla</shadedPattern>
</relocation>
<includes>
<include>com.qsl.Hello</include>
</includes>
</relocations>
</configuration>
然后打包得到 uber jar(qsl-a.jar),项目依赖从 A.jar 更改成 qsl-a.jar,B.jar 依赖继续保留,那么项目中可用的 Hello.class 就包括 。
com.qsl.Hello(B.jar) 。
com.qsla.Hello(qsl-a.jar) 。
问题是不是就得到解决了?更实际的案例,敬请期待我下篇博客 。
项目原始jar
以及 项目依赖的所有jar
,而输出目标是 uber-jar
,所以 maven-shade-plugin 的规则对 项目原始jar
是无效的minimizeJar
针对的只是 class
,其他类型的文件不受此约束最后此篇关于maven插件之maven-shade-plugin,解决同包同名class共存问题的神器的文章就讲到这里了,如果你想了解更多关于maven插件之maven-shade-plugin,解决同包同名class共存问题的神器的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
通过终端,您可以使用命令 - “SetFile -a B 文件名” 以编程方式,我认为我应该通过[[NSFileManager defaultManager] createDirectoryAtPat
嗨,正在尝试书中的一些示例:Practical Graph mining with R对于子图挖掘: library(subgraphMining) library(igraph) graph1 =
代码中的相同问题: class Foo { int getIntProperty () { ... } CustomObject getObjectProperty () { ... }
所以这可能是一个愚蠢的问题,但它已经困扰我一段时间了。 使用 React,我创建了两个组件(Buttons.js 和 Message.js),每个组件都有一个导出。但是,现在我希望将这两个组件用作 n
从今天早上开始,我发现我无法再从某个范围安装任何 NPM 包(或任何具有依赖项的包)。例如,如果我输入 npm i webpack 我会收到以下错误... npm ERR! code E401 npm
我在这里搜索过,Angular 2, @ngtools/webpack, AOT ,但对我不起作用。我运行了 npm install 命令。我正在做的是创建一个新的 Angular 2 项目。当我运行
情况: 我有一个 Swift 包,将其命名为 lib。 lib 位于其自己的存储库中。在lib的仓库中,有一堆本地包;也就是说,这些包是在 lib 中定义的,使用本地路径依赖格式 .package(p
我想在工作中学习和使用nodejs,但是在使用 de npm 命令安装模块/包时遇到网络问题。我是否可以使用我的家用计算机构建完整的 Node js 包,然后将其安装在另一台计算机(我的工作场所计算机
我需要将一些 .tar.bz2 格式的非 Python 包转换为 Anaconda/miniConda .egg 文件并安装它们。为此,我需要一个适用于 Windows 的 bld.bat 文件。互联
我需要共享库文件 libthrift-0.9.3.so 作为其他包的依赖项。我在构建 thrift-0.9.3 包时看到编译问题(我确实从 https://thrift.apache.org/down
我尝试在 R 版本 3.5.0 中安装“arcgisbinding”包。但是我失败了,得到以下错误和警告。 Installing package into ‘C:/Users/Lenovo/Docum
我尝试在 R 版本 3.5.0 中安装“arcgisbinding”包。但是我失败了,得到以下错误和警告。 Installing package into ‘C:/Users/Lenovo/Docum
我试图在 flutter 中测试这个应用程序,但我无法运行该应用程序,因为出现此错误“名称‘Page’在库‘package:burn_off/widgets/page.dart’和‘package’中
试图理解和学习如何编写包...用我一直使用的东西进行测试,记录... 您能帮我理解为什么“日志”变量不起作用...并且屏幕上没有日志记录吗? 谢谢! 主要文件: #!/opt/local/bin/py
我尝试运行此使用 Google 云的代码。 import signal import sys from google.cloud import language, exceptions # creat
我想知道是否有人找到了一个很好的 R 包来分析眼动追踪数据? 我遇到了 eyetrackR,但据我所知,没有可用的英文支持文档: http://read.psych.uni-potsdam.de/pm
我正在 R 上制作一个包。我有两个函数共享一个变量(全局)。 如何将其导入到包中? 例如, m<-0 f<-function() { m <- m+1 } g<-function() { m <- m
我用 C 为 Lua 编写了很多模块。每个模块都包含一个 Lua 用户数据类型,我像这样加载和使用它们: A = require("A") B = require("B") a = A.new(3,{
我正在尝试在 R 中的 Ubuntu 上安装 xlsx 包,以便使用允许在 R 中插入链接然后将它们导出到 Excel 的功能。 话虽如此,我根本无法安装该软件包。 显然它必须与 rJava 一起使用
我想在 Haskell 中做一些蒙特卡洛分析。我希望能够编写这样的代码: do n <- poisson lambda xs <- replicateM n $ normal mu sigma
我是一名优秀的程序员,十分优秀!