获取JNI头文件
写一个代表C++库的接口的Java Class
package cn.task.service.jni;
public class JniTest {
public JniTest() {
// TODO Auto-generated constructor stub
}
static {
System.loadLibrary("jniTest"); //jniTest就是要加载的动态库的名字,这是相对路径加载方式
}
public static native int demo_add(int a , int b);
public static native String demo_print_string(String s);
}
将它转化为class
javac JniTest.java
再转化为JNI头文件.h
,注意这一步要在<projectName>/src/main/java
的位置进行
javah -classpath . -jni cn.task.service.jni.JniTest
得到如下头文件cn_task_service_jni_JniTest.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class cn_ac_baqis_baqisCloud_task_service_jni_JniTest */
#ifndef _Included_cn_ac_baqis_baqisCloud_task_service_jni_JniTest
#define _Included_cn_ac_baqis_baqisCloud_task_service_jni_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: cn_task_service_jni_JniTest
* Method: demo_add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_cn_task_service_jni_JniTest_demo_1add
(JNIEnv *, jclass, jint, jint);
/*
* Class: cn_task_service_jni_JniTest
* Method: demo_print_string
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_cn_task_service_jni_JniTest_demo_1print_1string
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
打包并部署C++ library
C/C++库要根据得到的头文件的需要格式编写
#include "cn_task_service_jni_JniTest.h"
JNIEXPORT jint JNICALL Java_cn_task_service_jni_JniTest_demo_1add
(JNIEnv * env, jclass jc, jint a, jint b) {
return a+b;
}
JNIEXPORT jstring JNICALL Java_cn_task_service_jni_JniTest_demo_1print_1string
(JNIEnv * env, jclass jc, jstring s) {
return s;
}
因为头文件引用了jni.h
,打包前需要找到你的jni.h
和jni_md.h
的资源地址,一般是在JAVA资源路径的include
下
我们在Java里想要调取的资源的名字是jniTest
,所以我们希望生成名字为jniTest.dll
(Windows)或libjniTest.so
(Linux)的动态库
Windows打包
gcc -fPIC -I "C:\Program Files\Java\jdk1.8.0_231\include" -I "C:\Program Files\Java\jdk1.8.0_231\include\win32" -shared -o jniTest.dll anyName.c
Windows上的JAVA默认会从当前文件夹内找资源,因此只要将动态库放在当前项目内就可以被找到
Linux打包
生成.so
,注意名字前必须加lib
在可以在加载时被找到
gcc -fPIC -I /usr/lib/jvm/java-8-openjdk-amd64/include -I /usr/lib/jvm/java-8-openjdk-amd64/include/linux -shared -o libjniTest.so anyName.c
使用Linux时,为了可以在运行时被JAVA找到,我们还需要为我们的资源设置地址$LD_LIBRARY_PATH
打开 /etc/profile
,写入LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/helpers/native
,并在终端输入source /etc/profile
启用更新
将生成的.so
库放入/helpers/native
,JAVA便会在运行时找到它,打包后的jar
也可以成功找到它
Springboot中使用C/C++库
写一个Controller
package cn.task.controller;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.task.service.jni.JniTestService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@Controller
@Api(tags = "C++ Simulator internface")
@RequestMapping(value="/simulator")
public class JniTestController {
@Resource
@Autowired
private JniTestService jniTestService ;
@RequestMapping(value="/simulateAdd", method=RequestMethod.GET)
@ApiOperation("Add to numbers")
@ResponseBody
public int simulateAdd( @RequestParam("a")int a, @RequestParam("b")int b) {
return jniTestService .demoAdd(a, b);
}
@RequestMapping(value="/simulatePrint", method=RequestMethod.GET)
@ApiOperation("Print a String")
@ResponseBody
public String simulatePrint(@RequestParam("s")String s) {
return jniTestService .demoPrint(s);
}
}
再写一个处理Controller请求的Service,调用最早写的C/C++库的接口Class
package cn.task.service.jni;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class JniTestService {
public static JniTest jni;
public JniTestService () {
// TODO Auto-generated constructor stub
}
public int demoAdd(int a, int b) {
int i = jni.demo_add(a, b);
return i;
}
public String demoPrint(String s) {
String a = jni.demo_print_string(s);
return a;
}
}
启动SpringBoot服务器,并向服务器发送请求
Swagger-UI demo
网友评论