最近在给一个Java项目打包的时候,使用了maven-shade-plugin插件,不过打包之后执行的时候,一直报错: 找不到onnxruntime-engine。通过查找资料发现,是因为我的项目中同时引入了pytorch-engine和onnxruntime-engine类库,这两个类库的 META-INF/services中都有名为ai.djl.engine.EngineProvider的文件。
ai.djl.engine.EngineProvider文件是在Java SPI机制下,通过与接口同名的文件来记录具体的实现类。当有多个同名文件时,说明该接口有多个实现类,没有配置资源转换类的情况下,这些接口的实现类会相互覆盖,最终导致有的实现类找不到。
maven-shade-plugin插件在给项目打包的时候,可以通过在pom.xml中配置如下资源转换类来避免实现类的相互覆盖:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<!-- 绑定 Maven 生命周期的 package 阶段 -->
<phase>package</phase>
<goals>
<!-- package 阶段执行时,让其调用插件的 repackage 目标 -->
<goal>shade</goal>
</goals>
</execution>
</executions>
<!-- 设置插件属性 -->
<configuration>
<transformers>
<!-- 设置 Java SPI 追加而非覆盖 -->
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</plugin>
按照此配置打包的jar中,解压之后会发现 META-INF/services的ai.djl.engine.EngineProvider文件中有两个实现类。
另外,在用maven-shade-plugin打包的时候,只会打包classpath路径中的资源,项目根目录下的其他资源文件不会打包到jar中,这时需要通过IncludeResourceTransformer资源转换类来将非classpath路径中的资源中的文件打包进jar中,配置如下
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<!-- 文件在jar包中的路径及文件名 -->
<resource>models/ch_PP-OCRv4_det_infer/inference.onnx</resource>
<!-- 要打包文件在项目中的相对路径 -->
<file>models/ch_PP-OCRv4_det_infer/inference.onnx</file>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>models/ch_PP-OCRv4_rec_infer/inference.onnx</resource>
<file>models/ch_PP-OCRv4_rec_infer/inference.onnx</file>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
<resource>models/ch_PP-OCRv4_rec_infer/dict.txt</resource>
<file>models/ch_PP-OCRv4_rec_infer/dict.txt</file>
</transformer>