版本
- java21
- springboot3
- ffmpeg 7.1-1.5.11
- opencv 4.10.0-1.5.11
pom.xml
<properties>
<bytedeco.version>1.5.11</bytedeco.version>
<opencv-platform.version>4.10.0-1.5.11</opencv-platform.version>
<ffmpeg-platform.version>7.1-1.5.11</ffmpeg-platform.version>
<javacpp.platform.linux-x86_64>linux-x86_64</javacpp.platform.linux-x86_64>
<javacpp.platform.windows-x86_64>windows-x86_64</javacpp.platform.windows-x86_64>
<javacpp.platform>${javacpp.platform.linux-x86_64}</javacpp.platform>
</properties>
<dependencies>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>${bytedeco.version}</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>${bytedeco.version}</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>${opencv-platform.version}</version>
<classifier>${javacpp.platform}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>${ffmpeg-platform.version}</version>
<classifier>${javacpp.platform}</classifier>
</dependency>
</dependencies>
springboot打包后jar包结构(简化后)
可以看到在spring的jar包中的BOOT-INF/lib
目录下ffmpeg-7.1-1.5.11-linux-x86_64.jar
和opencv-4.10.0-1.5.11-linux-x86_64.jar
中,已经存在运行所需的so依赖。正常来说在运行时就会加载这些库。
但是实际运行时它并没有到
ffmpeg-7.1-1.5.11-linux-x86_64.jar
和opencv-4.10.0-1.5.11-linux-x86_64.jar
中查找所需的库,出现了以下错误:Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.UnsatisfiedLinkError: no jniavutil in java.library.path: /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib [in thread "http-nio-8100-exec-1"] at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2458) ~[na:na] at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:916) ~[na:na] at java.base/java.lang.System.loadLibrary(System.java:2059) ~[na:na] at org.bytedeco.javacpp.Loader.loadLibrary(Loader.java:1832) ~[javacpp-1.5.11.jar!/:1.5.11] at org.bytedeco.javacpp.Loader.load(Loader.java:1423) ~[javacpp-1.5.11.jar!/:1.5.11] at org.bytedeco.javacpp.Loader.load(Loader.java:1234) ~[javacpp-1.5.11.jar!/:1.5.11] at org.bytedeco.javacpp.Loader.load(Loader.java:1210) ~[javacpp-1.5.11.jar!/:1.5.11] at org.bytedeco.ffmpeg.global.avutil.<clinit>(avutil.java:14) ~[ffmpeg-7.1-1.5.11.jar!/:7.1-1.5.11] at java.base/java.lang.Class.forName0(Native Method) ~[na:na] at java.base/java.lang.Class.forName(Class.java:534) ~[na:na] at java.base/java.lang.Class.forName(Class.java:513) ~[na:na] at org.bytedeco.javacpp.Loader.load(Loader.java:1289) ~[javacpp-1.5.11.jar!/:1.5.11] at org.bytedeco.javacpp.Loader.load(Loader.java:1234) ~[javacpp-1.5.11.jar!/:1.5.11] at org.bytedeco.javacpp.Loader.load(Loader.java:1226) ~[javacpp-1.5.11.jar!/:1.5.11] at org.bytedeco.javacv.FFmpegFrameGrabber.tryLoad(FFmpegFrameGrabber.java:111) ~[javacv-1.5.11.jar!/:1.5.11] at org.bytedeco.javacv.FFmpegFrameGrabber.<clinit>(FFmpegFrameGrabber.java:137) ~[javacv-1.5.11.jar!/:1.5.11] ... 179 common frames omitted
在Windows中上开发环境中没有问题他可以找到,但是打包成jar运行就出错了,我觉得可能是因为在开发工具中运行时工具自动设置了classpath,在调用ffmpeg的时候,因为ffmpeg-7.1-1.5.11-linux-x86_64.jar
和opencv-4.10.0-1.5.11-linux-x86_64.jar
在classpath中,所以能找到相关库。
但是在打成jar后,运行的命令是java -jar xxx.jar
此时ffmpeg
和opencv
就不在classpath中,所以找不到,不知道这样理解对不对。
idea 开发环境运行时的命令
C:\app\java\java-21\bin\java.exe -XX:TieredStopAtLevel=1 -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true "-Dmanagement.endpoints.jmx.exposure.include=*" -classpath "D:\app_data\maven_repo\org\bytedeco\javacpp\1.5.11\javacpp-1.5.11.jar; D:\app_data\maven_repo\org\bytedeco\javacv\1.5.11\javacv-1.5.11.jar; D:\app_data\maven_repo\org\bytedeco\opencv\4.10.0-1.5.11\opencv-4.10.0-1.5.11.jar; D:\app_data\maven_repo\org\bytedeco\ffmpeg\7.1-1.5.11\ffmpeg-7.1-1.5.11.jar; D:\app_data\maven_repo\org\bytedeco\opencv\4.10.0-1.5.11\opencv-4.10.0-1.5.11-windows-x86_64.jar; D:\app_data\maven_repo\org\bytedeco\ffmpeg\7.1-1.5.11\ffmpeg-7.1-1.5.11-windows-x86_64.jar; com.demo.CommonOssApplication
问题
- 在打包后如何加载jar包lib目录中的so文件?
- 因为最终需要构建成docker镜像,也尝试过将这些so文件添加到docker基础镜像中,但是在开发环境可以正常运行,那打包后应该也有办法让他正常运行,而不是吧so文件添加到基础镜像中或jar包外部。
问题的核心在于JavaCPP的Loader类需要能够找到并解压这些本地库文件。当你在开发环境运行时,IDE添加了所有的依赖到classpath中,所以能正常加载。但打包成jar后,这些嵌套在jar包中的本地库无法被直接访问。
1. 在应用启动时编程方式配置JavaCPP
创建一个配置类,在应用启动时执行:
2. 自定义Docker镜像构建
可以创建一个自定义的Dockerfile:
这样的组合解决方案既能处理开发环境的问题,也能确保在Docker容器中正常运行,而不必修改基础镜像。
值得注意的问题:
-Dorg.bytedeco.javacpp.maxphysicalbytes=0
来防止内存限制问题或者可以尝试
通过Java系统属性配置JavaCPP
在启动应用时添加以下系统属性: