獲取JNI頭文件
寫一個代表C++庫的接口的Java Class
package cn.task.service.jni;
public class JniTest {
public JniTest() {
// TODO Auto-generated constructor stub
}
static {
System.loadLibrary("jniTest"); //jniTest就是要加載的動態(tài)庫的名字,這是相對路徑加載方式
}
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)的動態(tài)庫
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默認會從當前文件夾內找資源,因此只要將動態(tài)庫放在當前項目內就可以被找到
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服務器,并向服務器發(fā)送請求

Swagger-UI demo