JAVA通过JNI调用C++程序实践

整体思路:将需要调用的C++函数在java中声明一个对应的native函数,利用javah生成对应的h头文件,用C++封装成动态链接库,提供给java调用
实践步骤:

1.声明需要调用的C++函数在java中对应的native函数,这里只有两个是native函数,只要这2个函数在动态库中能找到就可以了:

package com.ylzhang.service.config;

/**
 * YlzhangJNITestNative 
 *  * @author ylzhang
 * @desc
 * @creatTime 16:29 2017/7/24
 */
public class YlzhangJNITestNative {

    public native int testOne(String str);

    public native String testTwo(String str);

    private String nowFilePath;

    public YlzhangJNITestNative (String libPath) throws Exception {
        if (null == libPath) {
            NativeLibraryLoader.getInstance().loadLibrary();
        } else {
            System.out.println("[加载] 外部动态库:" + libPath);
            System.load(libPath);
        }
    }

    public String getNowFilePath() {
        return nowFilePath;
    }

    public void setNowFilePath(String nowFilePath) {
        this.nowFilePath = nowFilePath;
    }
}

2.生成native函数对应的头文件,注意这里我是有包名的,javah生成的时候,需要带上路径(不带路径的话,会找不到native函数在C++中的实现),另外我只需要testOne和testTwo有对应头文件函数就可以了,其他函数不需要头文件函数:
2.1 新建/com/ylzhang/service/config/YlzhangJNITestNative.java 文件,内容如下:

package com.ylzhang.service.config;

/**
 * YlzhangJNITestNative 
 *
 * @author ylzhang
 * @desc
 * @creatTime 16:29 2017/7/24
 */
public class YlzhangJNITestNative {

    public native int testOne(String str);

    public native String testTwo(String str);

}

2.2 生成对应的class文件,运行:

javac YlzhangJNITestNative.java

2.3 然后回到com路径的上一级,运行:

javah com.ylzhang.service.config.YlzhangJNITestNative

此时应该会生成 com_ylzhang_service_config_YlzhangJNITestNative.h 文件,内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_ylzhang_service_config_YlzhangJNITestNative */

#ifndef _Included_com_ylzhang_service_config_YlzhangJNITestNative
#define _Included_com_ylzhang_service_config_YlzhangJNITestNative
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ylzhang_service_config_YlzhangJNITestNative
 * Method:    testOne
 * Signature: (Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_ylzhang_service_config_YlzhangJNITestNative_testOne
  (JNIEnv *, jobject, jstring);

/*
 * Class:     com_ylzhang_service_config_YlzhangJNITestNative
 * Method:    testTwo
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ylzhang_service_config_YlzhangJNITestNative_testTwo
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

3.编写对应的C++代码实现上面的头文件函数,并生成动态链接库。例如:C++项目中,新建一个头文件,myJava.h,将com_ylzhang_service_config_YlzhangJNITestNative.h内容复制进去,编写对应的myJava.cpp 实现myJava.h的函数。

myJava.cpp文件如下:

#include "myJava.h"
#include <string>


JNIEXPORT jint JNICALL Java_com_ylzhang_service_config_YlzhangJNITestNative_testOne
  (JNIEnv *env, jobject o, jstring s) {
    const char* szStr = (env)->GetStringUTFChars(s,0);
    int i = MyCppFuncOne(szStr); //调用C++中的其他函数
    (env)->ReleaseStringUTFChars(s, szStr );
    return (jint)i;
}

JNIEXPORT jstring JNICALL Java_com_ylzhang_service_config_YlzhangJNITestNative_testTwo
  (JNIEnv *env, jobject o, jstring s){
    const char* szStr = (env)->GetStringUTFChars(s,0);
    string sResult;
    char* pcResult = NULL;
    int iret = MyCppFuncTwo(szStr,pcResult);
    if(pcResult != NULL) {
        sResult = pcResult;
        deleteMem(pcResult);
    }
    (env)->ReleaseStringUTFChars(s,szStr);
    jstring jstr = (env)->NewStringUTF(sResult.c_str());
    return jstr;
}

int MyCppFuncTwo(const char* pStr, char*& pResult){//todo 实现}

int MyCppFuncOne(const char* pStr){//todo 实现}

4.生成动态链接库,上文中的libPath是绝对路径,java就可以调用啦。这里放一个福利,我们可以将动态库打包进jar中,在不指定外部动态库路径的时候,默认加载jar中的动态库。

NativeLibraryLoader类

package com.ylzhang.service.config;


import com.ylzhang.service.util.EnvironmentUtils;

import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

/**
 * NativeLibraryLoader
 *
 * @author ylzhang
 * @desc
 * @creatTime 14:53 2017/7/21
 */
public class NativeLibraryLoader {


    private static final NativeLibraryLoader instance = new NativeLibraryLoader();
    private static boolean initialized = false;

    public static NativeLibraryLoader getInstance() {
        return instance;
    }

    public synchronized void loadLibrary() throws Exception {
        loadLibraryFromJar(null);
    }

    private void loadLibraryFromJar(final String tmpDir)
            throws Exception {
        if (!initialized) {
            String nativeLibName = EnvironmentUtils.getJniLibraryName();
            System.out.println("[加载] 内置动态库");
            final File temp;
            if (tmpDir == null || tmpDir.equals("")) {
                temp = File.createTempFile(EnvironmentUtils.getFilePrefix(), EnvironmentUtils.getJniLibraryExtension());
            } else {
                temp = new File(tmpDir, nativeLibName);
                if (!temp.createNewFile()) {
                    throw new RuntimeException("File: " + temp.getAbsolutePath()
                            + " could not be created.");
                }
            }

            if (!temp.exists()) {
                throw new RuntimeException("File " + temp.getAbsolutePath() + " does not exist.");
            } else {
                temp.deleteOnExit();
            }

            try (final InputStream is = getClass().getClassLoader().
                    getResourceAsStream(nativeLibName)) {
                if (is == null) {
                    throw new RuntimeException(nativeLibName + " was not found inside JAR.");
                } else {
                    Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
                }
            }
            System.load(temp.getAbsolutePath());
            initialized = true;
        }
    }

}

EnvironmentUtils类

package com.ylzhang.service.util;

/**
 * EnvironmentUtils
 * 获取到平台信息 win unix mac
 *
 * @author ylzhang
 * @desc
 * @creatTime 14:58 2017/7/21
 */
public class EnvironmentUtils {

    private static String OS = System.getProperty("os.name").toLowerCase();
    private static String ARCH = System.getProperty("os.arch").toLowerCase();
    private static String LIBARAY_NAME_PREFIX = "libontSearch4j";

    public static boolean isWindows() {
        return (OS.contains("win"));
    }

    public static boolean isMac() {
        return (OS.contains("mac"));
    }

    public static boolean isUnix() {
        return (OS.contains("nix") ||
                OS.contains("nux") ||
                OS.contains("aix"));
    }

    private static boolean is64Bit() {
        return (ARCH.indexOf("64") > 0);
    }

    public static String getJniLibraryName() throws Exception {
        System.out.println("[平台] os:" + OS + " arch:" + ARCH);
        if (isUnix()) {
            if (is64Bit()) {
                return LIBARAY_NAME_PREFIX + ".so";
            }
            throw new UnsupportedOperationException("only support x64");
        } else if (isWindows()) {
            if (is64Bit()) {
                return LIBARAY_NAME_PREFIX + ".dll";
            }
            throw new UnsupportedOperationException("only support x64");
        } else if (isMac()) {
            throw new UnsupportedOperationException("mac is not support");
        }
        throw new UnsupportedOperationException();
    }

    public static String getJniLibraryExtension() {
        return (isWindows()) ? ".dll" : ".so";
    }

    public static String getFilePrefix() {
        return LIBARAY_NAME_PREFIX;
    }
}

猜你喜欢

转载自blog.csdn.net/zeroctu/article/details/76548990
今日推荐