【JNA】java springboot 动态读取动态库

news2024/9/22 14:49:39

【JNA】java springboot 动态读取动态库

  • 创建名为dynamic-lib-load.xml的文件
  • 资源目录结构如下
  • 工具类LibraryLoad
  • DynamicParseUtil工具类
  • 调用

我们在使用第三方动态库 时长出现动态库无法读取jar包内的动态库文件,以下代码希望对大家有帮助

  • 废话不多说,上代码:
  • 此处以大华监控为例

创建名为dynamic-lib-load.xml的文件

<?xml version="1.0" encoding="UTF-8" ?>
<dynamic-lib>
    <win64>
        <lib>avnetsdk</lib>
        <lib>dhconfigsdk</lib>
        <lib>dhnetsdk</lib>
        <lib>dhplay</lib>
        <lib>ImageAlg</lib>
        <lib>Infra</lib>
        <lib>IvsDrawer</lib>
        <lib>StreamConvertor</lib>
        <lib>jninetsdk</lib>
    </win64>
    <win32>
        <lib>avnetsdk</lib>
        <lib>dhconfigsdk</lib>
        <lib>dhnetsdk</lib>
        <lib>dhplay</lib>
        <lib>Infra</lib>
        <lib>ImageAlg</lib>
        <lib>StreamConvertor</lib>
        <lib>jninetsdk</lib>
    </win32>
    <linux64>
        <lib>avnetsdk</lib>
        <lib>dhnetsdk</lib>
        <lib>dhconfigsdk</lib>
        <lib>StreamConvertor</lib>
        <lib>jninetsdk</lib>
    </linux64>
    <linux32>
        <lib>avnetsdk</lib>
        <lib>dhconfigsdk</lib>
        <lib>dhnetsdk</lib>
        <lib>StreamConvertor</lib>
        <lib>jninetsdk</lib>
    </linux32>
    <mac64>
        <lib>avnetsdk</lib>
        <lib>dhnetsdk</lib>
        <lib>dhconfigsdk</lib>
        <lib>StreamConvertor</lib>
    </mac64>
</dynamic-lib>

资源目录结构如下

在这里插入图片描述

工具类LibraryLoad

@Slf4j
public class LibraryLoad {
    private static final String ARCH_WINDOWS = "win";
    private static final String ARCH_LINUX = "linux";
    private static final String ARCH_MAC = "mac";
    private static final int PREFIX_64 = 64;
    private static final int PREFIX_32 = 32;
    private static final String PREFIX_ARM = "ARM";
    private static final String EXTERNAL_WIN = ".dll";
    private static final String EXTERNAL_LINUX = ".so";
    private static final String EXTERNAL_MAC = ".dylib";
    private static DynamicParseUtil dynamicParseUtil;
    /**
     * 当前读取的目录
     */
    private static String currentFold;
    /**
     * 动态库需要写入的目录
     */
    private static String EXTRACT_PATH = System.getProperty("java.io.tmpdir");

    private static boolean written = false;

    /**
     * 设置动态库写入的路径,适用于需要自定义加载路径的用户
     *
     * @param path 动态库写入的文件夹,从该文件夹下加载sdk的动态库
     */
    public static void setExtractPath(String path) {
        EXTRACT_PATH = path;
    }

    public static String getExtractPath() {
        return EXTRACT_PATH;

    }

    /**
     * 动态库路径
     */
    private static String INNER_PATH;

    // private static final String EXTERNAL_MAC = ".so";

    private static String extractNetSDKLib(String libName) {
        return extractLibrary(libName);
    }

    public static String getLoadLibrary(String libraryName) {
        currentFold = getLibraryFold();
        if (dynamicParseUtil == null) {
            try {
                dynamicParseUtil =
                        new DynamicParseUtil(
                                LibraryLoad.class.getClassLoader().getResourceAsStream("dynamic-lib-load.xml"));
                if (!written) {
                    for (String libName : dynamicParseUtil.getLibsSystem(currentFold)) {
                        extractLibrary(libName);
                    }
                    written = true;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String fullName = getLibraryName(libraryName);
        String path = EXTRACT_PATH;
        if (!(EXTRACT_PATH.endsWith("/") || EXTRACT_PATH.endsWith("\\"))) {
            path = EXTRACT_PATH + "/";
        }
        log.info("load library: " + path + fullName);
        return path + fullName;
    }

    /**
     * 将jar包里的动态库写入到系统缓存目录,使用绝对路径加载动态库
     *
     * @param libName
     * @return
     */
    private static String extractLibrary(String libName) {
        return extractLibrary("", libName);
    }

    /**
     * 相对路径文件夹
     *
     * @param relativePath 相对路径
     * @param libName      动态库路径
     * @return
     */
    private static String extractLibrary(String relativePath, String libName) {
        if (libName.trim().equals("")) {
            return "";
        }
        String libFullName = getLibraryName(libName);
        String dir = getLibraryFold();
        if (!(relativePath.endsWith("/") || relativePath.endsWith("\\"))) {
            relativePath = relativePath + "/";
        }
        String fileName = relativePath + "libs/" + dir + "/" + libFullName;
        InputStream in = LibraryLoad.class.getResourceAsStream(fileName);
        BufferedInputStream reader;
        FileOutputStream writer;
        File extractedLibFile = null;
        try {
            if (in == null) {
                in = new FileInputStream(fileName);
                if (in == null) {
                    return "";
                }
            }
            String nativeTempDir = EXTRACT_PATH;
            if (!(nativeTempDir.endsWith("/") || nativeTempDir.endsWith("\\"))) {
                nativeTempDir = nativeTempDir + "/";
            }
            extractedLibFile = new File(nativeTempDir + libFullName);
            reader = new BufferedInputStream(in);
            writer = new FileOutputStream(extractedLibFile);
            byte[] buffer = new byte[1024];
            while (true) {
                int len = reader.read(buffer);
                if (len == 0 || len == -1) break;
                writer.write(buffer, 0, len);
            }
            reader.close();
            writer.close();
            in.close();
        } catch (Exception e) {
            log.error("dynamic file[ "
                    + fileName
                    + " ] not found in project.please ensure you need this library.");
        }
        return extractedLibFile != null ? extractedLibFile.getAbsolutePath() : "";
    }

    /**
     * 获取动态库完整名称
     *
     * @param libName
     * @return
     */
    private static String getLibraryName(String libName) {
        String dir = currentFold;
        String libPrefix = "";
        String libExtension = EXTERNAL_WIN;

        if (!dir.contains("win")) {
            libPrefix = "lib";
            if (dir.contains("linux")) {
                libExtension = EXTERNAL_LINUX;
                log.info("当前为LINUX环境");
            } else {
                // libExtension=".dylib";
                libExtension = EXTERNAL_MAC;
                log.info("当前为MAC环境");
            }
        }
        log.info("当前为win环境");
        libName = dynamicParseUtil.compareLibName(currentFold, libName);
        // 动态库以lib开头,则不添加lib前缀
        // 以lib开头的库则不添加lib前缀
        return (libName.startsWith("lib") ? "" : libPrefix) + libName + libExtension;
    }

    // 获取系统对应的动态库文件夹
    private static String getLibraryFold() {
        String osType;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().startsWith("linux")) {
            osType = ARCH_LINUX;
        } else if (osName.toLowerCase().startsWith("mac")
                || osName.toLowerCase().startsWith("darwin")) {
            osType = ARCH_MAC;
        } else if (osName.toLowerCase().startsWith("windows")) {
            osType = ARCH_WINDOWS;
        } else {
            osType = "";
        }
        String arch = System.getProperty("os.arch");
        arch = arch.toLowerCase().trim();
        if ("i386".equals(arch) || "i686".equals(arch) || "x86".equals(arch)) {
            arch = PREFIX_32 + "";
        } else if ("x86_64".equals(arch) || "amd64".equals(arch)) {
            arch = PREFIX_64 + "";
        } else if (arch.startsWith("arm")) {
            arch = PREFIX_ARM + "";
        }
        return osType + arch;
    }
}

DynamicParseUtil工具类

public class DynamicParseUtil {
    private DynamicLibParseHandler handler;
    private SAXParserFactory saxParserFactory;
    private SAXParser saxParser;

    /**
     * 适配各系统动态库名称大小写不同,以及lib前缀造成的找不到库的问题
     *
     * @param currentSystem 当前系统:win64,win32,linux64,linux32,mac64
     * @param libName       动态库名称
     * @return
     */
    public String compareLibName(String currentSystem, String libName) {
        String dynamicLibName = libName;
        List<String> libs = handler.getLibsBySystem(currentSystem);
        if (currentSystem.toLowerCase().contains("win")) {
            return findLibs(libs, libName);
        }
        if (libName.startsWith("lib")) {
            dynamicLibName = libName.substring(3);
        }
        return findLibs(libs, dynamicLibName);
    }

    private String findLibs(List<String> libs, String libName) {
        for (String lib : libs) {
            if (libName.equalsIgnoreCase(lib)) {
                return lib;
            }
        }
        return "";
    }

    public List<String> getLibsSystem(String system) {
        return handler.getLibsBySystem(system);
    }

    private DynamicParseUtil() throws ParserConfigurationException {
        // 获取SAX分析器的工厂实例,专门负责创建SAXParser分析器
        saxParserFactory = SAXParserFactory.newInstance();
        // 获取SAXParser分析器的实例
        try {
            saxParser = saxParserFactory.newSAXParser();
            handler = new DynamicLibParseHandler();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public DynamicParseUtil(InputStream inputSteam)
            throws ParserConfigurationException, IOException, SAXException {
        this();
        saxParser.parse(inputSteam, handler);
    }

    /**
     * xml解析handler
     */
    private class DynamicLibParseHandler extends DefaultHandler {
        private HashMap<String, List<String>> dynamics = new HashMap<String, List<String>>();
        private List<String> systems =
                Arrays.asList("win64", "win32", "linux64", "linux32", "mac64", "linuxARM");
        private String currentDynamicSystem;
        private List<String> libs;

        public List<String> getLibsBySystem(String system) {
            return dynamics.get(system);
        }

        @Override
        public void startDocument() throws SAXException {
            super.startDocument();
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes)
                throws SAXException {
            super.startElement(uri, localName, qName, attributes);
            if (systems.contains(qName)) {
                currentDynamicSystem = qName;
                if (libs == null) {
                    libs = new ArrayList<String>();
                }
            }
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            super.endElement(uri, localName, qName);
            if (systems.contains(qName)) {
                // 保存到hashmap中
                dynamics.put(currentDynamicSystem, libs);
                // 清除libs
                libs = null;
            }
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            super.characters(ch, start, length);
            String lib = new String(ch, start, length);
            if (!lib.trim().isEmpty()) {
                libs.add(lib);
            }
        }
    }
}

调用

public interface NetSDKLib extends Library {

    NetSDKLib NETSDK_INSTANCE = Native.load(LibraryLoad.getLoadLibrary("dhnetsdk"), NetSDKLib.class);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/69101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【王道计算机网络笔记】数据链路层-局域网广域网

文章目录局域网局域网拓扑结构局域网传输介质局域网介质访问控制方法局域网的分类以太网以太网提供无连接、不可靠的服务以太网传输介质与拓扑结构的发展10BASE-T以太网适配器与MAC地址以太网的MAC帧高速以太网IEEE802标准MAC子层和LLC子层IEEE802.11有固定基础设施无线局域网无…

嵌入式:ARM体系结构详解

文章目录指令集与指令集架构主要计算机指令集架构PC及服务器领域嵌入式领域新生代ARM体系结构的演变ARM发展的历程指令集与指令集架构 指令&#xff1a;就是指挥计算机工作的命令&#xff0c;程序就是一系列按一定顺序排列的指令&#xff0c;计算机就是通过执行程序中的指令来…

11. softmax回归的简洁实现

通过深度学习框架的高级API也能更方便地实现softmax回归模型。 继续使用Fashion-MNIST数据集&#xff0c;并保持批量大小为256。 import torch from torch import nn from d2l import torch as d2lbatch_size 256 train_iter, test_iter d2l.load_data_fashion_mnist(batch…

在IDEA中配置Maven

文章目录Maven 简介Maven 下载与安装修改Maven配置文件Maven文件目录的含义配置IDEA的MavenMaven 简介 Maven 项目对象模型(POM)&#xff0c;可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外&#x…

数据库审核工具SQLE接口调用

点击上方蓝字关注我接上文数据库审核接口SQLE的探索使用&#xff0c;本次自定义接口进行调用&#xff0c;实现需求。1、创建自定义审核接口因直接调用SQLE的审核接口&#xff0c;会出现token过期&#xff0c;且审核及结果查询接口是分开的&#xff0c;因此&#xff0c;出于以上…

Mock模拟数据动态字节码编译插件优化

模块介绍 dmc-plugin-java 动态编译字节码 关于动态编译字节码技术参考&#xff1a; https://blog.csdn.net/huxiang19851114/article/details/127881616 优化如下&#xff1a; 动态文本类改为界面配置及数据库保存 数据库表结构&#xff1a; DROP TABLE IF EXISTS compi…

leetcode刷题 log day56(编辑距离总结篇~

583. 两个字符串的删除操作 【思路】这道题只有删除操作&#xff0c;两个字符串相等时&#xff0c;步数不变&#xff0c;不相等时&#xff0c;只能做删除操作&#xff0c;删除有三种情况&#xff1a;删除 word1 或删除 word2 或者两个字符串都删除&#xff0c;取三种情况的最小…

sytem clock for ctrl ms task and us/ms delay

Cortex-M3 的内核中包含一个 SysTick 时钟。SysTick 为一个 24 位递减计数器&#xff0c;SysTick 设定初值并使能后&#xff0c;每经过 1 个系统时钟周期&#xff0c;计数值就减 1。计数到 0 时&#xff0c;SysTick 计数器自动重装初值并继续计数&#xff0c;同时内部的 COUNTF…

网页性能优化

网页性能优化 文章目录网页性能优化[TOC](文章目录)前言1.前端脚本优化1.1 减少重绘、回流1.2 缓存dom选择与计算1.3 使用事件委托而不是批量绑定2.渲染优化2.1 使用CSS3开启GPU硬件加速提升网站动画渲染性能2.2 touchmove、scroll、input事件添加防抖3.加载优化3.1 合并小图片…

怎么修改图片分辨率提高清晰度?如何调整图片dpi分辨率?

下载的图片有时候会比较模糊&#xff0c;想要改变图片清晰度的话就需要调整图片分辨率&#xff0c;很多小伙伴都不知道怎么去修改分辨率&#xff08;在线修改照片分辨率&#xff08;DPI&#xff09; 调整图片DPI 照片dpi修改工具-压缩图&#xff09;。今天小编就教大家一个非常…

关系抽取(三)实体关系联合抽取:TPlinker

参考&#xff1a; NLP系列之封闭域联合抽取&#xff1a;CasRel、TPLinker、PRGC、PURE、OneRel&#xff0c;实在是太卷了&#xff01; - 知乎 (zhihu.com)NLP 关系抽取 — 概念、入门、论文、总结 TPlinker 论文&#xff1a;PLinker: Single-stage Joint Extraction of Entit…

乐观锁思想在 JAVA 中的实现——CAS

前言 生活中我们看待一个事物总有不同的态度&#xff0c;比如半瓶水&#xff0c;悲观的人会觉得只有半瓶水了&#xff0c;而乐观的人则会认为还有半瓶水呢。很多技术思想往往源于生活&#xff0c;因此在多个线程并发访问数据的时候&#xff0c;有了悲观锁和乐观锁。 悲观锁认为…

FinClip11月产品更新:FIDE 插件开发功能优化;开发者文档英文版上线

不知不觉 22 年进入尾声&#xff0c;通过一年的不断打磨&#xff0c;FinClip 也在不断成长&#xff0c;现在&#xff0c;让我们看看过去的 11 月&#xff0c;FinClip 又有了哪些新的变化。 产品方面的相关动向&#x1f447;&#x1f447;&#x1f447; FIDE 插件开发功能优化…

【LeetCode每日一题:1775. 通过最少操作次数使数组的和相等~~~贪心+思维题】

题目描述 给你两个长度可能不等的整数数组 nums1 和 nums2 。两个数组中的所有值都在 1 到 6 之间&#xff08;包含 1 和 6&#xff09;。 每次操作中&#xff0c;你可以选择 任意 数组中的任意一个整数&#xff0c;将它变成 1 到 6 之间 任意 的值&#xff08;包含 1 和 6&a…

另一种在ARM/x86架构处理器上部署WebDAV服务器的方法

引言 最近搞了个矿渣&#xff0c;处理器是国产的RK3328&#xff0c;四核A53架构&#xff0c;64位的&#xff0c;性能太好了&#xff0c;装了个OpenWRT&#xff0c;想用来当nas用&#xff0c;但是我发现&#xff0c;竟然没有合适的文件服务器&#xff0c;局域网内用SMB确实可以…

Java并发编程—CompletableFuture的常用方法(建议收藏)

在过去的一段时间里&#xff0c;博主一直在给大家分享多线程并发编程里面的关键CompletableFfuture类的各种技术点&#xff0c;并发编程作为java开发里面关键点之一&#xff0c;也是大家向上提升重要的一点&#xff1b;对于CompletableFuture的学习一定要学到位&#xff0c;前面…

盘点 JDK 中基于 CAS 实现的原子类

前言 JDK 中提供了一系列的基于 CAS 实现的原子类&#xff0c;CAS 的全称是Compare-And-Swap&#xff0c;底层是lock cmpxchg指令&#xff0c;可以在单核和多核 CPU 下都能够保证比较交换的原子性。所以说&#xff0c;这些原子类都是线程安全的&#xff0c;而且是无锁并发&…

第4季5:图像sensor的驱动源码的编译

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 本文演示如何修改sensor的驱动源码&#xff0c;修改之后如何编译与运行。 一、sensor的注册接口分析 这部分内容见第4季4&#xff1a;图像sensor的驱动源码解析。 二、黑电平 关于黑电平的概念&a…

[附源码]计算机毕业设计抗疫医疗用品销售平台Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【电巢】电源管理芯片:国产化替代厂家竞逐千亿黄金赛道

前言 整个2022年三季度&#xff0c;全国新能源电动车的起火已高达600多起&#xff0c;同比上升了30%多&#xff0c;如果具体到每天来看&#xff0c;平均每天都有超过7起新能源电动车火灾发生。 7月22日&#xff0c;台湾省专业赛车手林某颖驾驶着一辆白色特斯拉Model X&#xff…