JNI介绍及原理
JVM封装了各种操作系统实际的差异性的同时,提供了jni技术,使得开发者可以通过java程序(代码)调用到操作系统相关的技术实现的库函数,从而与其他技术和系统交互,使用其他技术实现的系统的功能;同时其他技术和系统也可以通过jni提供的相应原生接口开调用java应用系统内部实现的功能。
在windows系统上,一般可执行的应用程序都是基于native的PE结构,windows上的jvm也是基于native结构实现的。Java应用体系都是构建于jvm之上。
有了JAVA标准平台的支持,使JNI模式更加易于实现和使用
JNI程序开发的一般操作步骤
- 编写带有native声明的方法的java类
- 使用javac命令编译所编写的java类
- 然后使用javah + java类名生成扩展名为h的头文件
- 使用C/C++实现本地方法
- 将C/C++编写的文件生成动态连接库
简单示例
ltp4j中不支持使用个性化分词模型,需要通过JNI的方式增加此功能
定义JAVA调用类接口
package edu.hit.ir.ltp4j;
import java.util.List;
public class CustomizedSegmentor
{
static
{
System.loadLibrary("customized_segmentor_jni");
}
public static native int create(String paramString1, String paramString2);
public static native int create(String paramString1, String paramString2, String paramString3);
public static native int segment(String paramString, List<String> paramList);
public static native void release();
}
编译JAVA类
javac edu/hit/ir/ltp4j/CustomizedSegmentor.java
产生c/c++原生函数的头文件
javah -jni edu.hit.ir.ltp4j.CustomizedSegmentor
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class edu_hit_ir_ltp4j_CustomizedSegmentor */
#ifndef _Included_edu_hit_ir_ltp4j_CustomizedSegmentor
#define _Included_edu_hit_ir_ltp4j_CustomizedSegmentor
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: edu_hit_ir_ltp4j_CustomizedSegmentor
* Method: create
* Signature: (Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_create__Ljava_lang_String_2Ljava_lang_String_2
(JNIEnv *, jclass, jstring, jstring);
/*
* Class: edu_hit_ir_ltp4j_CustomizedSegmentor
* Method: create
* Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_create__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2
(JNIEnv *, jclass, jstring, jstring, jstring);
/*
* Class: edu_hit_ir_ltp4j_CustomizedSegmentor
* Method: segment
* Signature: (Ljava/lang/String;Ljava/util/List;)I
*/
JNIEXPORT jint JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_segment
(JNIEnv *, jclass, jstring, jobject);
/*
* Class: edu_hit_ir_ltp4j_CustomizedSegmentor
* Method: release
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_release
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
编写cpp文件
直接调用segment_dll.h里的函数 参考:https://github.com/HIT-SCIR/ltp/blob/master/src/segmentor/segment_dll.h,https://github.com/HIT-SCIR/ltp4j/blob/master/jni/edu_hit_ir_ltp4j_Segmentor.h,https://github.com/HIT-SCIR/ltp4j/blob/master/jni/segment_jni.cpp
// segmentor_jni.cpp : Defines the exported functions for the DLL application.
//
#include "ltp/segment_dll.h"
#include "edu_hit_ir_ltp4j_CustomizedSegmentor.h"
#include "string_to_jstring.hpp"
#include <iostream>
#include <string>
#include <vector>
using namespace std;
static void * segmentor = NULL;
JNIEXPORT jint JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_create__Ljava_lang_String_2Ljava_lang_String_2
(JNIEnv * env, jclass obj, jstring model_path1, jstring model_path2){
const char * str_model1 = env->GetStringUTFChars( model_path1 , 0);
const char * str_model2 = env->GetStringUTFChars( model_path2 , 0);
if(!segmentor){
segmentor = customized_segmentor_create_segmentor(str_model1,str_model2);
}
else{
customized_segmentor_release_segmentor(segmentor);
segmentor = customized_segmentor_create_segmentor(str_model1,str_model2);
}
env->ReleaseStringUTFChars( model_path1, str_model1);
env->ReleaseStringUTFChars( model_path2, str_model2);
if(segmentor) {
return 1;
}
return -1;
}
JNIEXPORT jint JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_create__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2
(JNIEnv * env, jclass obj, jstring model_path1, jstring model_path2, jstring lexicon_path){
const char * str_model1 = env->GetStringUTFChars( model_path1 , 0);
const char * str_model2 = env->GetStringUTFChars( model_path2 , 0);
const char * str_lexicon = env->GetStringUTFChars( lexicon_path , 0);
if(!segmentor){
segmentor = customized_segmentor_create_segmentor(str_model1,str_model2,str_lexicon);
}
else{
customized_segmentor_release_segmentor(segmentor);
segmentor = customized_segmentor_create_segmentor(str_model1,str_model2,str_lexicon);
}
env->ReleaseStringUTFChars( model_path1, str_model1);
env->ReleaseStringUTFChars( model_path2, str_model2);
env->ReleaseStringUTFChars( lexicon_path, str_lexicon);
if(segmentor) {
return 1;
}
return -1;
}
JNIEXPORT jint JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_segment
(JNIEnv * env, jclass obj, jstring sent, jobject array_words){
jclass array_list = env->GetObjectClass(array_words);
jmethodID list_add = env->GetMethodID(array_list,"add","(Ljava/lang/Object;)Z");
const char * str_sent = env->GetStringUTFChars( sent , 0);
std::string sentence(str_sent);
std::vector<std::string> words;
int len = customized_segmentor_segment(segmentor,sentence,words);
for(int i = 0;i<len;i++){
jobject tmp = stringToJstring(env,words[i].c_str());
env->CallBooleanMethod(array_words,list_add,tmp);
}
env->ReleaseStringUTFChars(sent, str_sent);
return len;
}
JNIEXPORT void JNICALL Java_edu_hit_ir_ltp4j_CustomizedSegmentor_release
(JNIEnv * env, jclass obj){
customized_segmentor_release_segmentor(segmentor);
segmentor = NULL;
}
编译,产生so文件
vi CMakeLists.txt 在文件中添加如下内容:
add_library (customized_segmentor_jni SHARED ${JNI_SOURCE_DIR}/customized_segment_jni.cpp)
target_link_libraries (customized_segmentor_jni segmentor)
采用cmake进行编译
JAVA调用示例
static {
if (CustomizedSegmentor.create("customized.model", "cws.model") < 0) {
System.err.println("load failed");
System.exit(1);
}
}
List words = new ArrayList();
int size = CustomizedSegmentor.segment(line, words);
CustomizedSegmentor.release();
参考
http://baike.baidu.com/link?url=rthf0sbZ4t_EAojpchZ0D9tQmmoMVR672uyVBiXwR2huPdZK_YIR2n2Tc5hHp3oPddE_9Jn_yYtULHE8S-km__
http://www.iteye.com/topic/304594
http://www.cnblogs.com/mandroid/archive/2011/06/15/2081093.html