美文网首页
Java SpringBoot引入C/C++库(基于JNI)

Java SpringBoot引入C/C++库(基于JNI)

作者: Lyudmilalala | 来源:发表于2021-04-12 19:24 被阅读0次

    获取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.hjni_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

    相关文章

      网友评论

          本文标题:Java SpringBoot引入C/C++库(基于JNI)

          本文链接:https://www.haomeiwen.com/subject/guoxlltx.html