美文网首页
Java 和 C++之间互相调用

Java 和 C++之间互相调用

作者: 大龄程序员在帝都 | 来源:发表于2017-04-06 15:41 被阅读411次

    如何在Java和C++之间进行互相调用呢?

    应用场景没有什么好说到了,Java调用底层SDK,SDK代码基本都是C或者C++编写,以及后期的物联网技术,很多都是和底层硬件相关系的,底层硬件相关系的编程,自然要用到C或者C++,上层的androidp平台都是用Java编写的,这个之间如何进行互动,就非常重要了。

    这里提供两个思路,jni和jna,据说jna这个框架,实在底层的jni技术之上进行的一个封装,所以还是对jni技术有一个比较好的理解,才是至关重要的!!!

    REF
    这个作者的系列文章很给力,可参考
    jni调用参考
    jni调用详细参考

    直接上demo吧!

    package jni;
    
    public class RecorderHandler {
         static  {
            try{
              System.out.println("load jni library start... ");
                      //装载对应的类库,因为我的是mac系统所以生成的是.dylib文件,如果是linux/unix生成的是.so文件
              System.load("/Users/xxx/Documents/rt/libRecorderHandler.dylib");
             // System.load("/root/ww/libRecorderHandler.so");
              System.out.println("load jni library completed");
            }catch(Exception e){
                System.out.println("load jni lib occur error:  " + e.getMessage());
            }
        }
        
        
        /**
         * 传入录制命令
         * @param type ref  enum type
         * @param conf_id  id
         * @param conf_alias 别名
         * @param force_jvb jvb
         * @return
         */
        public native int doRecorder(int type,String  conf_id,String conf_alias,String force_jvb);
        
        /**
         * C++回调上传java
         */
       public native void callback();
     
    }
    
    

    如上定义了两个native方法,第一个native方法是直接调用C++代码,第二个native是c++调用java ,声明的这个方法直接调用,我再在C++中编写调用Java部分的代码

    package dubbo.service.impl;
    import javax.annotation.Resource;
    import jni.RecorderHandler;
    import org.springframework.beans.factory.annotation.Autowired;
    import recorder.service.RecorderService;
    import service.RecorderResultService;
    import service.TestService;
    import entity.Recorder;
    //dubbo暴漏接口注解的两种方式,这是一种方式,是通过注解暴漏服务,另外一种是通过配置文件xml的形式暴漏服务
    //@Service
    @Resource
    public class RecorderServiceImpl implements RecorderService{
    
        //用@Reference和@Autowired具有同样的效果,只是在配置文件中需要不同的配置
        //@Reference
        @Autowired
        private TestService testService;
        @Autowired
        private RecorderResultService recorderResultService;
        
        public enum Type{
            RECORDSTART,RECORDSTOP,RECORDPAUSE,RECORDRESUME
        } 
        
        
        
        public void startRecorder(String location) {
            // TODO Auto-generated method stub
            System.out.println("recorder  start now....." + "location is :  " + location);
            //录制完成记录录制结果:
            this.sendRecorderResult();
        }
        
        public void  sendRecorderResult(){
            try{
                
                RecorderHandler  recorderHandler = new RecorderHandler();
                System.out.println("uuuu");
                System.out.println("开始调用录制:  " + recorderHandler.doRecorder(Type.RECORDSTART.ordinal(),"aaa","bbb","ccc"));
                
            //执行回调
            recorderHandler.callback();
            
            }catch(Exception e){
                System.out.println("occur error : "+e.getMessage());
            }
        }
        
        public void recorderCallBack(String str,int i){
            //这里打印成功,代表c++调用java部分成功
            System.out.println("execute  calll back, str is " + str +", and i is " + i );
        }
    }
    
    

    如上是调用的接口:

    如何生成.so文件呢?
    首先生成头文件: .h文件,如何生成??
    生成java class文件以后,利用javah jni.RecorderHandler命令进行生成

    javah jni.RecorderHandler
    

    生成对应的.h文件如下:这个文件就是定义了一些native的方法头,是不允许修改的

    * DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class jni_RecorderHandler */
    
    #ifndef _Included_jni_RecorderHandler
    #define _Included_jni_RecorderHandler
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     jni_RecorderHandler
     * Method:    doRecorder
     * Signature: (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
     */
    JNIEXPORT jint JNICALL Java_jni_RecorderHandler_doRecorder
      (JNIEnv *, jobject, jint, jstring, jstring, jstring);
    
    /*
     * Class:     jni_RecorderHandler
     * Method:    callback
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_jni_RecorderHandler_callback
      (JNIEnv *, jobject);
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    

    编写对应的实现代码:里面包含了,对应的Java调用C++部分的代码,和C++调用Java部分的代码,,执行以下输出结果为:

    #include "jni_RecorderHandler.h"
    #include <string.h>
    #include<stdio.h>
    #include<stdlib.h>
    JNIEXPORT jint JNICALL Java_jni_RecorderHandler_doRecorder
      (JNIEnv *, jobject, jint, jstring, jstring, jstring)
    {
            return 9999;
    }
    
     JNIEXPORT void JNICALL Java_jni_RecorderHandler_callback
     (JNIEnv* env, jobject)
     {
    
        jclass clazz = NULL;
        jobject jobj = NULL;
        jmethodID mid_construct = NULL;
        jmethodID mid_instance = NULL;
        jstring str_arg = NULL;
    
        // 1、从classpath路径下搜索RecorderServiceImpl这个类,并返回该类的Class对象
        clazz = env->FindClass("dubbo/service/impl/RecorderServiceImpl");
        if (clazz == NULL) {
            printf("can not find 'dubbo.service.impl.RecorderServiceImpl.'class");
            return;
        }
    
            // 2、获取类的默认构造方法ID
        mid_construct = env->GetMethodID(clazz, "<init>","()V");
        if (mid_construct == NULL) {
            printf("can not  find default constrct method");
            return;
        }
    
        // 3、查找实例方法的ID
        mid_instance = env->GetMethodID(clazz, "recorderCallBack", "(Ljava/lang/String;I)V");
        if (mid_instance == NULL) {
              printf(" int dubbo.service.impl.RecorderServiceImpl.class can not find method recorderCallBack");
            return;
        }
    
        // 4、创建该类的实例
        jobj = env->NewObject(clazz,mid_construct);
        if (jobj == NULL) {
            return;
        }
    
         // 5、调用对象的实例方法
        str_arg = env->NewStringUTF("i am calling recorderCallBack method");
        env->CallVoidMethod(jobj,mid_instance,str_arg,200);
    
        // 删除局部引用
        env->DeleteLocalRef(clazz);
        env->DeleteLocalRef(jobj);
        env->DeleteLocalRef(str_arg);
      }
    

    编译命令可以保存为 complime.sh
    然后赋予执行权限: chmod +x complime.sh就可以用./complime.sh执行编译了!
    编译程序在mac上编译为.dylib文件

    g++ -shared -I /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/include  -I/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/include/darwin -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include jni_RecorderHandler.cpp -o libRecorderHandler.dylib
    

    在linux文件中编译为.so文件:

    g++ -shared -I /opt/jdk1.8.0_92/include -I/opt/jdk1.8.0_92/include/linux  -fPIC jni_RecorderHandler.cpp -o libRecorderHandler.so
    

    执行上面从程序,输入结果为:

    Paste_Image.png

    如上证明Java调用C++和C++调用Java都没有问题了。

    相关文章

      网友评论

          本文标题:Java 和 C++之间互相调用

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