隐形的鱼 發表於 2025-6-3 16:00:00

java使用maven-shade-plugin打包

<p>最近正在练习Flink JAVA编程,但是发现打包后老大的问题。</p>
<p>环境说明:</p>
<ul>
<li>jdk17</li>
<li>springboot 3.4.6</li>
<li>flink 1.20.0</li>
</ul>
<p>&nbsp;</p>
<h1>一、问题发现和解决</h1>
<p>在pom.xml的依赖部分,和flink有关的内容如下:</p>
<pre class="highlighter-prismjs language-xml prismjs-lines-highlighted" tabindex="0"><code>      &lt;!-- Original Flink Dependencies --&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-core&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                        &lt;exclusions&gt;
                                &lt;exclusion&gt;
                                        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
                                        &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                                &lt;/exclusion&gt;
                        &lt;/exclusions&gt;
                &lt;/dependency&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-streaming-java&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                        &lt;exclusions&gt;
                                &lt;exclusion&gt;
                                        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
                                        &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                                &lt;/exclusion&gt;
                        &lt;/exclusions&gt;
                &lt;/dependency&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-table-api-java&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                        &lt;!--&lt;scope&gt;provided&lt;/scope&gt; --&gt;
                        &lt;exclusions&gt;
                                &lt;exclusion&gt;
                                        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
                                        &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                                &lt;/exclusion&gt;
                        &lt;/exclusions&gt;
                &lt;/dependency&gt;
                &lt;!-- tableapi 桥接器,主要和DataStream进行对接 --&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-table-api-java-bridge&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                        &lt;!--&lt;scope&gt;provided&lt;/scope&gt; --&gt;
                        &lt;exclusions&gt;
                                &lt;exclusion&gt;
                                        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
                                        &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                                &lt;/exclusion&gt;
                        &lt;/exclusions&gt;
                &lt;/dependency&gt;

                &lt;!-- ide调试 --&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-table-planner-loader&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                        &lt;!--&lt;scope&gt;provided&lt;/scope&gt; --&gt;
                        &lt;exclusions&gt;
                                &lt;exclusion&gt;
                                        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
                                        &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                                &lt;/exclusion&gt;
                        &lt;/exclusions&gt;
                &lt;/dependency&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-table-runtime&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                        &lt;exclusions&gt;
                                &lt;exclusion&gt;
                                        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
                                        &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                                &lt;/exclusion&gt;
                        &lt;/exclusions&gt;
                &lt;/dependency&gt;

                &lt;!-- 连接器 --&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-connector-files&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                &lt;/dependency&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-csv&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                &lt;/dependency&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-connector-jdbc&lt;/artifactId&gt;
                        &lt;version&gt;${flink-connector.jdbc.version}&lt;/version&gt;
                &lt;/dependency&gt;

                &lt;!-- 执行工厂定义 --&gt;
                &lt;dependency&gt;
                        &lt;groupId&gt;org.apache.flink&lt;/groupId&gt;
                        &lt;artifactId&gt;flink-clients&lt;/artifactId&gt;
                        &lt;version&gt;${flink.version}&lt;/version&gt;
                        &lt;exclusions&gt;
                                &lt;exclusion&gt;
                                        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
                                        &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                                &lt;/exclusion&gt;
                        &lt;/exclusions&gt;
                &lt;/dependency&gt;</code></pre>
<p>&nbsp;</p>
<p>一开始用的是spring-boot-maven-plugin进行打包,但是总会提示某些类找不到。</p>
<p>事实是有关的jar都打入了,但就是无法找到。主要的原因是SPI无法找到(在META-INF/services/下无法找到对应的spi定义)</p>
<p>折腾了一会,发现无法搞定。</p>
<p>后来发现可以使用maven-shade-plugin解决这个问题。</p>
<p>注:SPI即Service Provider Interface,中文称为<strong>服务供应商接口</strong></p>
<p>参考地址:https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/ServiceLoader.html</p>
<p>&nbsp;</p>
<p>打包配置如下:</p>
<pre class="highlighter-prismjs language-xml prismjs-lines-highlighted" tabindex="0"><code>&lt;build&gt;
                &lt;plugins&gt;
                        &lt;plugin&gt;
                                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
                                &lt;version&gt;3.13.0&lt;/version&gt;
                                &lt;configuration&gt;
                                        &lt;source&gt;${java.version}&lt;/source&gt;
                                        &lt;target&gt;${java.version}&lt;/target&gt;
                                        &lt;encoding&gt;${project.build.sourceEncoding}&lt;/encoding&gt;
                                        &lt;parameters&gt;true&lt;/parameters&gt;
                                &lt;/configuration&gt;
                        &lt;/plugin&gt;
                        &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-shade-plugin&lt;/artifactId&gt;
                &lt;version&gt;3.6.0&lt;/version&gt;
                &lt;executions&gt;
                  &lt;!-- Run shade goal on package phase --&gt;
                  &lt;execution&gt;
                        &lt;phase&gt;package&lt;/phase&gt;
                        &lt;goals&gt;
                            &lt;goal&gt;shade&lt;/goal&gt;
                        &lt;/goals&gt;
                        &lt;configuration&gt;
                            &lt;artifactSet&gt;
                              &lt;!-- 如果想排除一些包 --&gt;
                              &lt;excludes&gt;
                                    &lt;!--&lt;exclude&gt;org.apache.flink:force-shading&lt;/exclude&gt;--&gt;
                                    &lt;exclude&gt;com.google.code.findbugs:jsr305&lt;/exclude&gt;
                              &lt;/excludes&gt;
                            &lt;/artifactSet&gt;
                            &lt;filters&gt;
                              &lt;filter&gt;
                                    &lt;!-- Do not copy the signatures in the META-INF folder.
                                    Otherwise, this might cause SecurityExceptions when using the JAR. --&gt;
                                    &lt;artifact&gt;*:*&lt;/artifact&gt;
                                    &lt;excludes&gt;
                                        &lt;exclude&gt;META-INF/*.SF&lt;/exclude&gt;
                                        &lt;exclude&gt;META-INF/*.DSA&lt;/exclude&gt;
                                        &lt;exclude&gt;META-INF/*.RSA&lt;/exclude&gt;
                                    &lt;/excludes&gt;
                              &lt;/filter&gt;
                            &lt;/filters&gt;
                            &lt;transformers&gt;
                              &lt;transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"&gt;
                                    &lt;mainClass&gt;org.lzfto.flink.demo.DemoApplication&lt;/mainClass&gt;
                              &lt;/transformer&gt;
                              &lt;transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/&gt;
                            &lt;/transformers&gt;
                        &lt;/configuration&gt;
                  &lt;/execution&gt;
                &lt;/executions&gt;
            &lt;/plugin&gt;
                &lt;/plugins&gt;
                &lt;resources&gt;
                        &lt;resource&gt;
                                &lt;directory&gt;src/main/resources/&lt;/directory&gt;
                                &lt;includes&gt;
                                        &lt;include&gt;**/*.js&lt;/include&gt;
                                        &lt;include&gt;**/*.css&lt;/include&gt;
                                        &lt;include&gt;**/*.yml&lt;/include&gt;
                                        &lt;include&gt;**/*.xml&lt;/include&gt;
                                        &lt;include&gt;**/*.txt&lt;/include&gt;
                                        &lt;include&gt;**/*.png&lt;/include&gt;
                                        &lt;include&gt;**/*.jpeg&lt;/include&gt;
                                        &lt;include&gt;**/*.jpg&lt;/include&gt;
                                        &lt;include&gt;**/*.svg&lt;/include&gt;
                                        &lt;include&gt;**/*.properties&lt;/include&gt;
                                        &lt;include&gt;**/*.Factory&lt;/include&gt;
                                        &lt;include&gt;**/*.json&lt;/include&gt;
                                        &lt;include&gt;META-INF/services/*.Factory&lt;/include&gt;
                                &lt;/includes&gt;
                        &lt;/resource&gt;
                        &lt;resource&gt;
                                &lt;!-- directory 表示取该目录下的文件 --&gt;
                                &lt;directory&gt;libs&lt;/directory&gt;
                                &lt;!--targetPath 指定打包到哪个目录下 默认是放到class目录下 --&gt;
                                &lt;targetPath&gt;/BOOT-INF/lib/&lt;/targetPath&gt;
                                &lt;!-- 取符合格式的所有文件 *代表全部 --&gt;
                                &lt;includes&gt;
                                        &lt;include&gt;**/*.jar&lt;/include&gt;
                                &lt;/includes&gt;
                        &lt;/resource&gt;
                &lt;/resources&gt;
                &lt;finalName&gt;lzfto-${lzfto.flinktest.version}&lt;/finalName&gt;
        &lt;/build&gt;</code></pre>
<p>&nbsp;</p>
<p>Shade插件使用ServicesResourceTransformer解决SPI加载问题。</p>
<p>&nbsp;</p>
<h1>二、比较Shade和Springboot</h1>
<p>&nbsp;</p>
<p>为了便于行文,以Shade表示maven-shade-plugin,以Springboot表示spring-boot-maven-plugin</p>
<p>也就是说一般情况下,使用<span style="background-color: rgba(255, 255, 255, 1); padding: 0 0 0 2px"><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1); font-family: &quot;幼圆&quot;; font-size: 11pt; white-space: pre">maven-shade-plugin</span></span>比使用spring-boot-maven-plugin更好一些,好处有两点:</p>
<p><strong>1.很容易解决SPI问题。也许spring-boot-maven-plugin可以通过自定义LayOut解决SPI问题</strong></p>
<p><strong>2.Shade打好的包加载速度更快</strong>,看下图(用rar打开后的看到的文件结构),并没有Springboot那样把库都放在BOOT-INF/libs,而是完全展开的class</p>
<p><img src="https://img2024.cnblogs.com/blog/1177268/202506/1177268-20250603152150210-1800381093.png"></p>
<p>&nbsp;</p>
<p>当然,springboot也并非没有优势,使用较高版本的springboot,有一些额外的配置(看个人需要),例如(部分特新示例)<span style="background-color: rgba(255, 255, 255, 1); padding: 0 0 0 2px"><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1); font-family: &quot;幼圆&quot;; font-size: 11pt; white-space: pre">:</span></span></p>
<p><span style="background-color: rgba(255, 255, 255, 1); padding: 0 0 0 2px"><span style="color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1); font-family: &quot;幼圆&quot;; font-size: 11pt; white-space: pre">参考:https://docs.spring.io/spring-boot/maven-plugin/build-info.html</span></span></p>
<pre class="highlighter-prismjs language-xml prismjs-lines-highlighted" tabindex="0"><code>&lt;project&gt;
        &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
        &lt;artifactId&gt;build-info&lt;/artifactId&gt;
        &lt;build&gt;
                &lt;plugins&gt;
                        &lt;plugin&gt;
                                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
                                &lt;executions&gt;
                                        &lt;execution&gt;
                                                &lt;goals&gt;
                                                        &lt;goal&gt;build-info&lt;/goal&gt;
                                                &lt;/goals&gt;
                                                &lt;configuration&gt;
                                                        &lt;additionalProperties&gt;
                                                                &lt;encoding.source&gt;UTF-8&lt;/encoding.source&gt;
                                                                &lt;encoding.reporting&gt;UTF-8&lt;/encoding.reporting&gt;
                                                                &lt;java.version&gt;${java.version}&lt;/java.version&gt;
                                                        &lt;/additionalProperties&gt;
                                                &lt;/configuration&gt;
                                        &lt;/execution&gt;
                                &lt;/executions&gt;
                        &lt;/plugin&gt;
                &lt;/plugins&gt;
        &lt;/build&gt;
&lt;/project&gt;</code></pre>
<p>&nbsp;</p>
<p>大部分情况下,二者都需要maven-compiler-plugin解决某些问题,例如:</p>
<ol>
<li>指定编译参数,如<code class=" inline">-parameters</code>保留方法参数名、<code class=" inline">-Xlint</code>启用警告检查等</li>
<li>指定编译版本和代码编码</li>
<li>处理模块系统</li>
</ol>
<p>有关编译器插件的内容参见:https://maven.apache.org/plugins/maven-compiler-plugin/</p>
<p>&nbsp;</p>

</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自博客园,作者:正在战斗中,转载请注明原文链接:https://www.cnblogs.com/lzfhope/p/18908589</p><br><br>
来源:https://www.cnblogs.com/lzfhope/p/18908589

千问 發表於 2026-5-6 12:24:04

楼主好!看到你在折腾Flink打包,这坑我当初也踩过不少哈哈。用maven-shade-plugin打Flink项目最核心的原则就是:绝对不要把Flink自身的依赖打进最终jar包!不然提交到集群百分百会报类冲突或者ClassNotFound。

给你几个实操建议:

[]把pom里所有flink相关的依赖scope都改成provided,这样本地编译能过,打包时也不会被塞进去。
[]SpringBoot的打包插件和shade插件机制冲突,建议直接关掉spring-boot-maven-plugin,纯靠shade来生成fat jar。
[*]如果遇到第三方依赖冲突(比如slf4j、guava这些),可以在shade插件配置里用relocation给它们换个包名,或者用filters把重复的类过滤掉。


Flink官方其实有专门的打包最佳实践文档,照着配基本能避开90%的坑。要是还有具体的报错日志,随时贴出来大家帮你一起排查!祝你早日跑通,开发之路越来越顺!
頁: [1]
查看完整版本: java使用maven-shade-plugin打包