在Spring Boot项目中如何正确加载FFmpeg和OpenCV的so依赖?

在spring boot项目中正确加载ffmpeg和opencv的so依赖是一个常见的问题。以下是基于java 21和spring boot 3版本的详细指南,介绍如何在打包后的项目中正确加载这些本地库。

我们首先来看一下项目的依赖配置和打包后的jar包结构:

项目依赖配置(pom.xml):

    1.5.11    4.10.0-1.5.11    7.1-1.5.11    linux-x86_64    windows-x86_64    ${javacpp.platform.linux-x86_64}            org.bytedeco        javacpp        ${bytedeco.version}                org.bytedeco        javacv        ${bytedeco.version}                org.bytedeco        opencv        ${opencv-platform.version}        ${javacpp.platform}                org.bytedeco        ffmpeg        ${ffmpeg-platform.version}        ${javacpp.platform}    

打包后jar包的结构(简化版):

在Spring Boot的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,这些jar包中包含了运行所需的so依赖。

然而,实际运行时系统并未从这些jar包中加载so文件,导致出现以下错误:

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"]

这个问题主要是因为JavaCPP的Loader类无法找到并解压这些本地库文件。在开发环境中,IDE会自动将所有依赖添加到classpath中,因此能够正常加载。但是打包成jar后,这些嵌套在jar包中的本地库无法被直接访问。

为了解决这个问题,可以采取以下两种方法:

1. 在应用启动时编程方式配置JavaCPP

可以通过创建一个Spring Boot配置类,在应用启动时执行JavaCPP配置:

package com.demo.config;

import org.bytedeco.javacpp.Loader;import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;

@Configurationpublic class JavaCppConfig {

@PostConstructpublic void init() {    // 设置JavaCPP提取本地库的目录    System.setProperty("org.bytedeco.javacpp.extract", "true");    System.setProperty("org.bytedeco.javacpp.extractDir", "/tmp/javacpp-native-libs");    // 预加载需要的库,这会触发JavaCPP从jar中提取库文件    try {        // 预加载FFmpeg相关库        Loader.load(org.bytedeco.ffmpeg.global.avutil.class);        Loader.load(org.bytedeco.ffmpeg.global.avcodec.class);        Loader.load(org.bytedeco.ffmpeg.global.avformat.class);        Loader.load(org.bytedeco.ffmpeg.global.swscale.class);        // 预加载OpenCV库        Loader.load(org.bytedeco.opencv.global.opencv_core.class);        Loader.load(org.bytedeco.opencv.global.opencv_imgproc.class);        System.out.println("Native libraries loaded successfully");    } catch (Exception e) {        System.err.println("Failed to load native libraries: " + e.getMessage());        e.printStackTrace();    }}

}

2. 自定义Docker镜像构建

为了在Docker环境中正确加载这些库,可以创建一个自定义的Dockerfile:

FROM openjdk:21-slim

安装程序运行所需的库

RUN apt-get update && apt-get install -y libgomp1 && rm -rf /var/lib/apt/lists/*

创建目录用于提取本地库

RUN mkdir -p /opt/javacpp-native-libsENV JAVACPP_EXTRACT_DIR=/opt/javacpp-native-libs

设置工作目录

WORKDIR /app

复制应用jar包

COPY target/*.jar app.jar

预先提取所有本地库到指定目录

RUN mkdir -p /tmp/extract && cd /tmp/extract && java -Dorg.bytedeco.javacpp.extract=true -Dorg.bytedeco.javacpp.extractDir=/opt/javacpp-native-libs -jar /app/app.jar --extract-native-libraries && rm -rf /tmp/extract

设置系统属性,指向提取的本地库位置

ENV JAVA_OPTS="-Dorg.bytedeco.javacpp.extractDir=/opt/javacpp-native-libs -Dorg.bytedeco.javacpp.extract=false"

启动应用

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

通过以上两种方法,我们可以在应用启动时确保正确加载FFmpeg和OpenCV的so文件,并且在Docker环境中也能正常运行,而无需修改基础镜像。

此外,还可以尝试通过在启动应用时添加系统属性来配置JavaCPP:

java -Djava.library.path=path/to/extracted/libs -Djavacpp.platform=linux-x86_64 -jar your-app.jar

需要注意的是,JavaCPP需要能够写入临时目录来提取本地库,同时在Docker环境中,可能需要添加-Dorg.bytedeco.javacpp.maxphysicalbytes=0来防止内存限制问题。如果使用多个平台(如Windows和Linux),请注意配置正确的platform属性。

在Spring Boot项目中如何正确加载FFmpeg和OpenCV的so依赖?

以上就是在Spring Boot项目中如何正确加载FFmpeg和OpenCV的so依赖?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1504354.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 02:47:18
下一篇 2025年12月20日 02:47:31

相关推荐

  • 使用 DataTables 和 JavaScript 数组创建可搜索列的表格

    本文档详细介绍了如何使用 DataTables 插件,结合 JavaScript 数组数据,创建具有列搜索功能的交互式表格。我们将从基础的 DataTables 初始化开始,逐步讲解如何配置列过滤器,并提供完整的代码示例,帮助开发者快速实现可搜索列的 DataTables 表格。 DataTable…

    2025年12月20日
    000
  • 使用 TypeORM 的 Raw SQL 实现灵活的 Where 查询条件

    本文旨在介绍如何在 TypeORM 中使用 Raw SQL 表达式来构建更灵活的 Where 查询条件,尤其是在需要避免大量 Or 条件时。通过 Raw 函数,你可以直接在 TypeORM 的查询选项中嵌入原生 SQL 片段,从而实现更精细的查询控制,避免构建过于庞大的 Where 数组,提升代码可…

    2025年12月20日
    000
  • TypeORM find选项中Raw SQL条件的高效应用

    本文探讨了在TypeORM的find选项中,如何利用Raw操作符高效处理复杂的查询条件,特别是涉及OR逻辑和IS NULL判断的场景,避免了使用QueryBuilder或构造冗长的where数组,从而简化了代码并提高了可读性。 在typeorm中进行数据查询时,find或findandcount等方…

    2025年12月20日
    000
  • js 怎么实现本地存储

    选择 localstorage 还是 sessionstorage 取决于数据生命周期需求,localstorage 用于长期保存如用户偏好设置,sessionstorage 用于会话期间临时存储如购物车信息;2. 本地存储限制包括:每域名约 5mb 容量、仅支持字符串类型需用 json.strin…

    2025年12月20日
    000
  • 如何编写第一个JS程序

    答案是编写第一个JavaScript程序最直接的方式是通过HTML文件中的标签嵌入代码,并用console.log()在控制台输出结果。具体步骤包括创建包含基本HTML结构的index.html文件,在中插入script标签并写下console.log(“Hello, JavaScrip…

    2025年12月20日
    000
  • TestCafe userVariables 配置与访问:避免常见拼写错误

    本文详细介绍了如何在TestCafe中使用userVariables配置自定义变量,并深入探讨了在测试脚本中访问这些变量时可能遇到的常见问题。通过具体案例,我们揭示了导致变量访问失败的根本原因——通常是由于属性名称拼写错误,而非异步加载问题。教程将指导您正确配置和安全访问userVariables,…

    2025年12月20日
    000
  • React/JavaScript中高效合并对象数组内嵌套数组的教程

    本教程详细讲解了如何在React/JavaScript应用中,将包含嵌套数组的对象数组扁平化为一个单一的数组。我们将分析传统方法可能遇到的问题,并重点介绍如何利用Array.prototype.reduce方法,以声明式和高效的方式实现这一数据转换,从而避免状态覆盖,确保数据完整性。 1. 引言:理…

    2025年12月20日
    000
  • React/JavaScript中合并对象数组内部嵌套数组的教程

    本文将详细介绍如何在React/JavaScript中高效地合并一个对象数组内部嵌套的子数组。当遇到包含多个对象,且每个对象又含有一个子数组的数据结构时,我们通常需要将所有这些子数组中的元素提取并合并成一个扁平化的单一数组。教程将通过分析常见的错误方法,并重点讲解如何利用Array.prototyp…

    2025年12月20日
    000
  • JavaScript/React中高效合并对象数组内嵌套数组的教程

    本教程探讨了在React应用中如何高效地合并对象数组内嵌套的子数组。我们将深入分析一种常见的错误,并提供基于JavaScript reduce 方法的专业解决方案,以及更现代的 flatMap 替代方案,旨在帮助开发者以清晰、可维护的方式处理复杂数据结构,确保数据扁平化以满足UI渲染需求。 理解问题…

    2025年12月20日
    000
  • JavaScript/React中合并对象数组内嵌数组的实用教程

    本教程将指导您如何在JavaScript和React应用中高效合并对象数组中嵌套的子数组。通过深入解析Array.prototype.reduce()方法,结合扩展运算符,我们将演示如何将多层嵌套的数据结构扁平化为一个单一的数组,避免常见的状态更新错误,并提供清晰的示例代码和最佳实践。 理解问题:嵌…

    2025年12月20日 好文分享
    000
  • JS如何实现模块模式?模块化的封装

    javascript实现模块化的核心是通过创建私有作用域来避免全局污染并提供清晰的公共接口,主要采用两种方式:一是利用函数作用域特性的立即执行函数(iife)模式,包括经典iife和揭示模块模式,适用于不支持es6模块的旧环境,具有良好的兼容性但语法冗余且缺乏静态分析支持;二是现代javascrip…

    2025年12月20日
    000
  • js 如何计算日期差值

    在 javascript 中计算日期差值的核心是利用 gettime() 获取毫秒时间戳并相减,1. 使用 gettime() 计算毫秒差可精确处理闰年和时区问题;2. 若需日历天数差,应先将日期归零至当天0点再计算;3. 通过定义常量(如 one_day = 24 60 60 * 1000)可灵活…

    2025年12月20日
    000
  • 什么是AC自动机?多模式字符串匹配

    AC自动机通过Trie树与Fail指针实现多模式串高效匹配,构建时先插入所有模式串形成Trie树,再用BFS建立Fail指针以实现失配跳转,匹配时对文本串一次扫描即可找出所有匹配模式,相比KMP在多模式场景下更高效。 AC自动机,简单来说,就是一个能同时匹配多个模式串的字符串匹配算法。它是在Trie…

    2025年12月20日
    000
  • JS如何实现动画?动画的帧控制

    JavaScript实现动画的核心是通过requestAnimationFrame与浏览器刷新同步,持续更新元素的transform或opacity等高性能CSS属性,避免回流和重绘,结合缓动函数提升视觉流畅度,同时可借助GSAP等动画库简化复杂动画的开发,实现高效、流畅的动画效果。 JavaScr…

    好文分享 2025年12月20日
    000
  • js 如何验证表单数据

    客户端表单验证的核心是通过javascript在提交前检查数据,提升用户体验并减轻服务器负担;2. 实现方式为监听表单提交事件,阻止默认行为,逐项验证输入字段并显示错误信息;3. 邮箱、密码、确认密码和同意条款等字段需分别进行非空、格式、长度、一致性及勾选状态校验;4. 使用isvalidemail…

    2025年12月20日
    000
  • JS如何实现主题切换?主题的变量

    答案:JavaScript通过操作CSS自定义属性和类名实现主题切换,并利用localStorage持久化用户偏好。首先在CSS中定义:root下的默认主题变量及.dark-theme等类中的覆盖变量,采用语义化命名如–color-primary提升可维护性;JavaScript在DOM…

    2025年12月20日
    000
  • js怎么实现模态框弹出

    模态框弹出时避免页面滚动的方法是通过javascript动态设置body的overflow为hidden,并在关闭时恢复;1. 打开模态框时,执行body.style.overflow = ‘hidden’,阻止页面滚动;2. 关闭模态框时,将overflow属性重置为空字符…

    2025年12月20日
    000
  • JS如何实现自适应布局

    JavaScript在自适应布局中弥补CSS的不足,通过动态操作DOM实现内容感知与结构重组,如响应视口变化、使用ResizeObserver监听元素尺寸、matchMedia控制断点逻辑,并结合节流、防抖和requestAnimationFrame优化性能,提升用户体验。 JavaScript在自…

    2025年12月20日
    000
  • JS如何实现尾递归优化?尾递归的特点

    尾递归的特点是递归调用位于函数体的最后一步,且其结果直接作为函数的返回值,无需在调用后进行额外计算,从而理论上可重用当前栈帧以避免栈溢出;在javascript中,尽管es6曾计划支持尾递归优化(tco),但因调试困难、性能收益有限及兼容性问题,主流引擎未普遍实现,因此实际运行中仍可能导致栈溢出;为…

    2025年12月20日
    000
  • TestCafe userVariables 获取不到元素问题的排查与解决

    本文旨在解决 TestCafe 中 userVariables 配置项无法正确获取的问题。通过分析常见错误原因,例如拼写错误,以及调试技巧,帮助开发者正确使用 userVariables,从而实现灵活的测试配置。 在使用 TestCafe 进行测试时,userVariables 配置项允许开发者在配…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信