Java 和 C++之间互相调用

如何在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 
/* 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 
#include
#include
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, "","()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

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

Java 和 C++之间互相调用_第1张图片
Paste_Image.png

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

你可能感兴趣的:(Java 和 C++之间互相调用)