Java调用第三方库JNA(C/C++)

news2024/11/19 22:40:41

GitHub - java-native-access/jna: Java Native Access  源代码

 在Java 中使用C语言库的传统做法是使用JNI编程。但是现在有更好的替代方案,即JNA(Java Native Access);JNA是一个开源的Java框架,是SUN公司推出的调用本地库方法的技术,是建立在经典的JIN基础之上的一个框架,之所以说它是JIN的替代者,是因为它大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成.JNA只需要我们写java代码,而不用编写JNI或者本地代码(适配用的.dll/.so),只需要在JAVA中编写一个接口和一些代码,作为.dll/.so的代理。就可以在java程序中调用DLL/SO;

============================================================================

JNA调研成果,需求是公司同事用C++写了一个红外测温SDK,编译成so文件后提供给客户使用。客户需要一个Linux环境用Java调用so库的一个demo,刚好就我一个懂点Java,所有有了这次调研。

因为JNA相关资料实在太少,而且我一没用过Linux,二没搞过虚拟机,所以在研发过程中踩了太多坑,每向前迈一步都要克服很多困难,所以想记录下来,也许能给其他需要的人借鉴一下,少走一点弯路。Linux虚拟机Java开发环境我就不介绍了,这方面资料还是挺多的,主要说一下JNA的使用。

JNA介绍和技术原理
JNA全称Java Native Access,是一个建立在经典的JNI技术之上的Java开源框架。

JNA提供工具用于调用c/c++动态函数库(如Window的dll以及linux的so)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标函数库的函数与结构,JNA将自动实现Java接口方法到函数的映射。

JNA使用一个小型的JNI库插桩程序来动态调用本地代码。开发者使用Java接口描述目标本地库的功能和结构,这使得它很容易利用本机平台的功能,而不会产生多平台配置和生成JNI代码的高开销。这样的性能、准确性和易用性显然受到很大的重视。

此外,JNA包括一个已与许多本地函数映射的平台库,以及一组简化本地访问的公用接口。

注意:

JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。

原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。

JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射,你不再需要编写C动态链接库。

也许这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。但总体影响不大,因为JNA也避免了JNI的一些平台配置的开销。

JNA数据类型映射表&模拟指针

在JNA中模拟指针,最常用到的就是Pointer类和PointerByReference类。Pointer类代表指向任何东西的指针,PointerByReference类表示指向指针的指针。Pointer类更加通用,事实上PointerByReference类内部也持有Pointer类的实例。
==================================================================

使用示例
环境说明:

jna-version:4.0.0(我用的是4.0.0版本)

jdk-version:1.8

java开发使用idea

JNA下载地址:https://github.com/java-native-access/jna.git

1、JNA简单调用
实现步骤
在Java类中创建一个接口CLibrary继承Library,

在CLibrary中加载so文件,

创建一个本地方法(对应so中的提供的native方法),

在main函数中用so实例(INSTANCE)调用本地创建的方法。

注意:下面是So库提供的可调用的方法.h头文件代码,JNA就是实现Java对这些函数的调用,后面的例子都是实现对这些方法的调用。
========================================================================

模拟OpenParams结构体,创建OpenParams继承Structure,设置成员变量,和C++结构体保持一致,参考映射表,char对应byte,int对应int,CapabilitySet也是结构体,属于结构体嵌套,CapabilitySet结构体模拟参考OpenParams,(JPEG_SIZE是枚举类型)C++中枚举类型和Java中不同,Java直接用int接收就可以。

创建两个内部类ByReference,ByValue继承OpenParams,分别实现接口Structure.ByReference、Structure.ByValue

覆盖getFieldOrder()方法,按顺序添加成员变量,一定要和C++结构体保持一致。

结构体传参分为值传递、引用传递(指针传递)

值传递使用ByValue

引用传递使用ByReference

在CLibrary中创建SCT_ChannelOpen(Pointer hChannel, OpenParams.ByRefrence openParams);
==========================================================================

从.h头文件中看到需要传入三个参数,hChannel指针,packetType枚举类型,param void指针,先看看C++中Packet Type,例如其中RTR_GetJpgFrame获取的数据param对应是一个FrameInfo结构体指针,所以要读取数据,我们要模拟结构体FrameInfo进行数据传递


============================================================================

现在模拟创建MtImgInfo结构体继承Structure,设置成员变量参考映射表,创建两个内部类ByReference、ByValue,获取数据,要想获取回调方法FunGetMtImgInfo()中其他数据,可以用同样的方法 

运行查看回调结果,成功输出回调结果

============================================================================

一、在使用springboot框架的时候,存在一个问题。就是我们配置yaml文件,需要单独提出来做参数修改。当然这个是可以通过spring.profiles.active的方式来配置dev,prod等环境的激活。但是我们如果存在环境不确定,或者需要启动脚本,启动项目的时候,这样通过jar的方式后续会处理很多工作。所以前期的集成工作还是很有必要的。

  二、这里有一个简单的例子,用于参数配置方式

  1)目录结构

2)需要的依赖包(pom.xml)

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

3)maven的构建过程 

<build>
        <finalName>assembly</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>
            <plugin>
                <!--主要使用的是maven提供的assembly插件完成-->
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <configuration>
                            <appendAssemblyId>false</appendAssemblyId>
                            <!--具体的配置文件-->
                            <descriptors>${project.basedir}/src/main/resources/assembly/package.xml</descriptors>
                        </configuration>
                        <id>make-assembly</id>
                        <!--绑定到maven操作类型上-->
                        <phase>package</phase>
                        <!--运行一次-->
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

 4)集成过程(package.xml)

<?xml version='1.0' encoding='UTF-8'?>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
    <!--打包名称,唯一标识-->
    <id>${project.build.finalName}</id>
    <!--打包格式,可以手动修改-->
    <formats>
        <format>tar.gz</format>
    </formats>
    <!--文件设置-->
    <fileSets>
        <fileSet>
            <!--目标目录,会处理目录里面的所有文件-->
            <directory>${project.basedir}/src/main/resources/config</directory>
            <!--相对于打包后的目录-->
            <outputDirectory>config</outputDirectory>
            <!--文件过滤-->
            <includes>
                <include>*.*</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.basedir}/src/main/resources/script</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>*.*</include>
            </includes>
            <!--文件权限-->
            <fileMode>0755</fileMode>
            <!--如果是脚本,一定要改为unix.如果是在windows上面编码,会出现dos编写问题-->
            <lineEnding>unix</lineEnding>
        </fileSet>
    </fileSets>
    <files>
        <!--包含打包后的jar文件,可以不加入<outputDirectory/>,默认打包的目录-->
        <file>
            <source>${project.build.directory}/${project.build.finalName}.jar</source>
        </file>
        <!--这种方式也可以进行文件处理,但是针对单文件-->
       <!-- <file>
            <source>${project.basedir}/src/main/resources/script/start.sh</source>
            <fileMode>0755</fileMode>
            <lineEnding>unix</lineEnding>
        </file>-->
    </files>
</assembly>

备注:具体的参数的意义可以参考官网:Apache Maven Assembly Plugin – Assembly

5)通过maven的package打包

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

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

相关文章

传染病学模型 | Matlab实现SEIRS传染病学模型 (SEIRS Epidemic Model)

文章目录 效果一览基本描述模型介绍程序设计参考资料效果一览 基本描述 传染病学模型 | Matlab实现SEIRS传染病学模型 (SEIRS Epidemic Model) 模型介绍 SEIRS是一种基于计算机模拟的传染病学模型,用于研究人群中传染病的传播和控制。与其他传染病学模型不同,SEIRS模型考虑了…

第二章.­ Learning to Answer Yes­_No

第二章. Learning to Answer Yes_No 2.1 Perceptron Hypothesis Set 1.机器学习流程图&#xff1a; 在机器学习的整个流程中&#xff0c;模型的选择(Hypothesis Set)是非常重要的&#xff0c;它决定了机器学习的最终效果。 2.常用的机器学习模型——感知机&#xff08;Percep…

L2-001 紧急救援(dijkstra算法练习)

作为一个城市的应急救援队伍的负责人&#xff0c;你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候&#xff0c;你的任务是带领你的…

Android 12系统源码_窗口管理(二)WindowManager对窗口的管理过程

前言 上一篇我们具体分析了窗口管理者WindowManagerService的启动流程&#xff0c;对于WindowManagerService有了一个初步的认识。在此基础上&#xff0c;我本打算应该进一步分析WindowManagerService是如何管理系统中的各种窗口的&#xff0c;然而由于Android系统的架构设计&…

如何搭建远程服务器-(cpolar)

文章目录 前言一、安装注册下载安装包认证开通指定端口监听开机自启动设置 二、使用步骤电脑端远程手机端远程 三、卸载软件安装说明&#xff1a; 总结 前言 之前已经有写到一篇文章《如何用树莓派搭建远程服务器 (zerotier)》&#xff0c;对此已经使用了很长一段时间。 优点…

MySQL 事务(w字)

目录 事务 首先我们来看一个简单的问题 什么是事务 为什么会出现事务 事务的版本支持 事务提交方式 事务常见操作方式 设置隔离级别 事物操作 事物结论 事务隔离级别 理解隔离性 隔离级别 查看与设置隔离性 注意可重复读【Repeatable Read】的可能问题&#xff…

AI数字人盛行,如何选择合适的AI数字人制作平台?

2023万象大会已然开启了直播&#xff0c;当AI照进生活、照亮你我&#xff0c;为我们的想象力插上翅膀&#xff0c;世界变得更加便捷、更加智能。可以说近年来&#xff0c;AI帮助人们解决了各种问题&#xff0c;在提高生产效率、改善生活质量等方面做出来很大的贡献&#xff0c;…

LeetCode: 二叉树的直径(java)

二叉树的直径 leetcode 543题。原题链接题目描述解题代码二叉树专题 leetcode 543题。原题链接 543题&#xff1a;二叉树的直径 题目描述 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也…

WICC · 出海嘉年华|嘉宾就位、话题揭晓,峰会 派对报名倒计时

双厨狂喜&#xff01;移步【融云全球互联网通信云】回复“地图”免费领 6 月 2 日即将在广州举办的“WICC 社交泛娱乐出海嘉年华”&#xff0c;将是一场集 WICC 通信行业大会高端峰会规格、前沿技术内容和社交泛娱乐出海务实场景落地、垂直圈子社交于一体的大型盛会。 大咖嘉…

【弹性分布式EMA】在智能电网中DoS攻击和虚假数据注入攻击(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Java并发体系-锁与同步-[1]

本阶段文章讲的略微深入&#xff0c;一些基础性问题不会讲解&#xff0c;如有基础性问题不懂&#xff0c;可自行查看我前面的文章&#xff0c;或者自行学习。本篇文章比较适合校招和社招的面试&#xff0c;笔者在2020年面试的过程中&#xff0c;也确实被问到了下面的一些问题。…

c++代码实现一个高性能内存池(超详细版本)

写在前面 本文的内存池代码是改编自Nginx的内存池源码&#xff0c;思路几乎一样。由于Nginx源码的变量命名我不喜欢&#xff0c;又没有注释&#xff0c;看得我很难受。想自己写一版容易理解的代码。这应该是全网独一份的超详细版本了&#xff08;笑~&#xff09;. 应用场景 …

Java线程中的常用方法

获取当前线程的方法 为线程设置名称 为线程设置优先级&#xff0c;优先级有10个级别&#xff0c;从1-10&#xff0c;能影响cpu调用线程的级别&#xff0c;但是不能决定。 /*** author 舒一笑* date 2023/5/25*/ public class Test03 {public static void main(String[] args) …

「OceanBase 4.1 体验」|docker-compose快速部署OceanBase数据库——筑梦之路

OceanBase数据库简介 官方网站&#xff1a;https://www.oceanbase.com/softwarecenter 大名鼎鼎的OceanBase数据库&#xff0c;在多个双十一购物节上历经验证&#xff0c;今天就来体验一下当前最新版本 4.1。 OceanBase 4.1 版本技术文档&#xff1a;https://www.oceanbase.c…

How-to-generate-kernel

文章目录 前言一、协方差判断卷积核相关性问题一: 不同的样本空间&#xff1f;问题二&#xff1a;计算方式&#xff1f;想法 二、整体流程三、BSConv-核内相似性 前言 在常规卷积的过程中找到相关性低的一部分卷积核&#xff0c;利用这部分卷积核结合深度可分离卷积搭建起新的…

mycat的安装及使用

2、mycat的安装及使用 1、mycat的安装 1、环境准备 ​ 本次课程使用的虚拟机环境是centos6.5 ​ 首先准备四台虚拟机&#xff0c;安装好mysql&#xff0c;方便后续做读写分离和主从复制。 192.168.85.111 node01 192.168.85.112 node02 192.168.85.113 node03 192.168.85.…

第3章“程序的机器级表示”:数据传送指令

文章目录 3.4 访问信息3.4.1 操作数指示符3.4.2 数据传送指令3.4.3 数据传送示例 3.4 访问信息 一个 IA32 中央处理单元&#xff08;CPU&#xff09;包含一组八个存储 32 位值的寄存器&#xff0c;这些寄存器用来存储整数数据和指针。 下图显示了这八个寄存器。它们的名字都是…

element-ui拖拽上传及问题解决(drag的使用注意事项)

element-ui拖拽上传及问题解决(drag的使用注意事项) 上传组件(:drag“true”) <template><el-uploadclass"avatar-uploader"action"":show-file-list"false":on-success"handleAvatarSuccess":before-upload"beforeAva…

如何获得铁粉(弯道超车的攻略)

文章目录 一、提供有价值的内容二、保持更新频率三、与读者互动四、优化SEO五、提供专栏订阅服务 CSDN(China Software Developer Network)是中国最大的IT社区和在线学习平台之一&#xff0c;成立于1999年。它是一个面向软件开发者的知识共享社区&#xff0c;提供有关编程语言、…

Docker容器技术|最强王者篇

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…