GitHub - java-native-access/jna: Java Native Access? 源代碼
?在Java 中使用C語言庫的傳統(tǒng)做法是使用JNI編程。但是現(xiàn)在有更好的替代方案,即JNA(Java Native Access);JNA是一個(gè)開源的Java框架,是SUN公司推出的調(diào)用本地庫方法的技術(shù),是建立在經(jīng)典的JIN基礎(chǔ)之上的一個(gè)框架,之所以說它是JIN的替代者,是因?yàn)樗蟠蠛?jiǎn)化了調(diào)用本地方法的過程,使用很方便,基本上不需要脫離Java環(huán)境就可以完成.JNA只需要我們寫java代碼,而不用編寫JNI或者本地代碼(適配用的.dll/.so),只需要在JAVA中編寫一個(gè)接口和一些代碼,作為.dll/.so的代理。就可以在java程序中調(diào)用DLL/SO;
============================================================================
JNA調(diào)研成果,需求是公司同事用C++寫了一個(gè)紅外測(cè)溫SDK,編譯成so文件后提供給客戶使用??蛻粜枰粋€(gè)Linux環(huán)境用Java調(diào)用so庫的一個(gè)demo,剛好就我一個(gè)懂點(diǎn)Java,所有有了這次調(diào)研。
因?yàn)镴NA相關(guān)資料實(shí)在太少,而且我一沒用過Linux,二沒搞過虛擬機(jī),所以在研發(fā)過程中踩了太多坑,每向前邁一步都要克服很多困難,所以想記錄下來,也許能給其他需要的人借鑒一下,少走一點(diǎn)彎路。Linux虛擬機(jī)Java開發(fā)環(huán)境我就不介紹了,這方面資料還是挺多的,主要說一下JNA的使用。
JNA介紹和技術(shù)原理
JNA全稱Java Native Access,是一個(gè)建立在經(jīng)典的JNI技術(shù)之上的Java開源框架。
JNA提供工具用于調(diào)用c/c++動(dòng)態(tài)函數(shù)庫(如Window的dll以及l(fā)inux的so)而不需要編寫任何Native/JNI代碼。開發(fā)人員只要在一個(gè)java接口中描述目標(biāo)函數(shù)庫的函數(shù)與結(jié)構(gòu),JNA將自動(dòng)實(shí)現(xiàn)Java接口方法到函數(shù)的映射。
JNA使用一個(gè)小型的JNI庫插樁程序來動(dòng)態(tài)調(diào)用本地代碼。開發(fā)者使用Java接口描述目標(biāo)本地庫的功能和結(jié)構(gòu),這使得它很容易利用本機(jī)平臺(tái)的功能,而不會(huì)產(chǎn)生多平臺(tái)配置和生成JNI代碼的高開銷。這樣的性能、準(zhǔn)確性和易用性顯然受到很大的重視。
此外,JNA包括一個(gè)已與許多本地函數(shù)映射的平臺(tái)庫,以及一組簡(jiǎn)化本地訪問的公用接口。
注意:
JNA是建立在JNI技術(shù)基礎(chǔ)之上的一個(gè)Java類庫,它使您可以方便地使用java直接訪問動(dòng)態(tài)鏈接庫中的函數(shù)。
原來使用JNI,你必須手工用C寫一個(gè)動(dòng)態(tài)鏈接庫,在C語言中映射Java的數(shù)據(jù)類型。
JNA中,它提供了一個(gè)動(dòng)態(tài)的C語言編寫的轉(zhuǎn)發(fā)器,可以自動(dòng)實(shí)現(xiàn)Java和C的數(shù)據(jù)類型映射,你不再需要編寫C動(dòng)態(tài)鏈接庫。
也許這也意味著,使用JNA技術(shù)比使用JNI技術(shù)調(diào)用動(dòng)態(tài)鏈接庫會(huì)有些微的性能損失。但總體影響不大,因?yàn)镴NA也避免了JNI的一些平臺(tái)配置的開銷。
JNA數(shù)據(jù)類型映射表&模擬指針
在JNA中模擬指針,最常用到的就是Pointer類和PointerByReference類。Pointer類代表指向任何東西的指針,PointerByReference類表示指向指針的指針。Pointer類更加通用,事實(shí)上PointerByReference類內(nèi)部也持有Pointer類的實(shí)例。
==================================================================
使用示例
環(huán)境說明:
jna-version:4.0.0(我用的是4.0.0版本)
jdk-version:1.8
java開發(fā)使用idea
JNA下載地址:https://github.com/java-native-access/jna.git
1、JNA簡(jiǎn)單調(diào)用
實(shí)現(xiàn)步驟
在Java類中創(chuàng)建一個(gè)接口CLibrary繼承Library,
在CLibrary中加載so文件,
創(chuàng)建一個(gè)本地方法(對(duì)應(yīng)so中的提供的native方法),
在main函數(shù)中用so實(shí)例(INSTANCE)調(diào)用本地創(chuàng)建的方法。
注意:下面是So庫提供的可調(diào)用的方法.h頭文件代碼,JNA就是實(shí)現(xiàn)Java對(duì)這些函數(shù)的調(diào)用,后面的例子都是實(shí)現(xiàn)對(duì)這些方法的調(diào)用。
========================================================================
模擬OpenParams結(jié)構(gòu)體,創(chuàng)建OpenParams繼承Structure,設(shè)置成員變量,和C++結(jié)構(gòu)體保持一致,參考映射表,char對(duì)應(yīng)byte,int對(duì)應(yīng)int,CapabilitySet也是結(jié)構(gòu)體,屬于結(jié)構(gòu)體嵌套,CapabilitySet結(jié)構(gòu)體模擬參考OpenParams,(JPEG_SIZE是枚舉類型)C++中枚舉類型和Java中不同,Java直接用int接收就可以。
創(chuàng)建兩個(gè)內(nèi)部類ByReference,ByValue繼承OpenParams,分別實(shí)現(xiàn)接口Structure.ByReference、Structure.ByValue
覆蓋getFieldOrder()方法,按順序添加成員變量,一定要和C++結(jié)構(gòu)體保持一致。
結(jié)構(gòu)體傳參分為值傳遞、引用傳遞(指針傳遞)
值傳遞使用ByValue
引用傳遞使用ByReference
在CLibrary中創(chuàng)建SCT_ChannelOpen(Pointer hChannel, OpenParams.ByRefrence openParams);
==========================================================================
從.h頭文件中看到需要傳入三個(gè)參數(shù),hChannel指針,packetType枚舉類型,param void指針,先看看C++中Packet Type,例如其中RTR_GetJpgFrame獲取的數(shù)據(jù)param對(duì)應(yīng)是一個(gè)FrameInfo結(jié)構(gòu)體指針,所以要讀取數(shù)據(jù),我們要模擬結(jié)構(gòu)體FrameInfo進(jìn)行數(shù)據(jù)傳遞
============================================================================
現(xiàn)在模擬創(chuàng)建MtImgInfo結(jié)構(gòu)體繼承Structure,設(shè)置成員變量參考映射表,創(chuàng)建兩個(gè)內(nèi)部類ByReference、ByValue,獲取數(shù)據(jù),要想獲取回調(diào)方法FunGetMtImgInfo()中其他數(shù)據(jù),可以用同樣的方法?
運(yùn)行查看回調(diào)結(jié)果,成功輸出回調(diào)結(jié)果
============================================================================
一、在使用springboot框架的時(shí)候,存在一個(gè)問題。就是我們配置yaml文件,需要單獨(dú)提出來做參數(shù)修改。當(dāng)然這個(gè)是可以通過spring.profiles.active的方式來配置dev,prod等環(huán)境的激活。但是我們?nèi)绻嬖诃h(huán)境不確定,或者需要啟動(dòng)腳本,啟動(dòng)項(xiàng)目的時(shí)候,這樣通過jar的方式后續(xù)會(huì)處理很多工作。所以前期的集成工作還是很有必要的。
二、這里有一個(gè)簡(jiǎn)單的例子,用于參數(shù)配置方式
1)目錄結(jié)構(gòu)
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的構(gòu)建過程?
<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>
<!--運(yùn)行一次-->
<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">
<!--打包名稱,唯一標(biāo)識(shí)-->
<id>${project.build.finalName}</id>
<!--打包格式,可以手動(dòng)修改-->
<formats>
<format>tar.gz</format>
</formats>
<!--文件設(shè)置-->
<fileSets>
<fileSet>
<!--目標(biāo)目錄,會(huì)處理目錄里面的所有文件-->
<directory>${project.basedir}/src/main/resources/config</directory>
<!--相對(duì)于打包后的目錄-->
<outputDirectory>config</outputDirectory>
<!--文件過濾-->
<includes>
<include>*.*</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/main/resources/script</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*.*</include>
</includes>
<!--文件權(quán)限-->
<fileMode>0755</fileMode>
<!--如果是腳本,一定要改為unix.如果是在windows上面編碼,會(huì)出現(xiàn)dos編寫問題-->
<lineEnding>unix</lineEnding>
</fileSet>
</fileSets>
<files>
<!--包含打包后的jar文件,可以不加入<outputDirectory/>,默認(rèn)打包的目錄-->
<file>
<source>${project.build.directory}/${project.build.finalName}.jar</source>
</file>
<!--這種方式也可以進(jìn)行文件處理,但是針對(duì)單文件-->
<!-- <file>
<source>${project.basedir}/src/main/resources/script/start.sh</source>
<fileMode>0755</fileMode>
<lineEnding>unix</lineEnding>
</file>-->
</files>
</assembly>
備注:具體的參數(shù)的意義可以參考官網(wǎng):Apache Maven Assembly Plugin – Assembly
5)通過maven的package打包
文章來源:http://www.zghlxwxcb.cn/news/detail-459226.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-459226.html
到了這里,關(guān)于Java調(diào)用第三方庫JNA(C/C++)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!