`
尤文武
  • 浏览: 9024 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

JNI实例

阅读更多
Java调用linux shell命令的时候,是通过Process来实现的,Process会新起一个进程,并且把主进程的内存信息拷贝一份到新的进程中,对于小的程序这种方式没问题,但如果项目足够大,就会导致系统内存不够程序退出的情况发生。

为了解决这个问题,有一个比较好的方案是JNI,这个时候并不需要重新起一个Process,也就不会存在备份内存的问题,下面是一个例子.

1.编写java类JNIHelper.java

package com.pracbiz;


public class JNIHelper
{
	static
	{
		System.loadLibrary("JNI");
	}
	
	public native String exec(String input);
	
	
	private static JNIHelper instance;

    private JNIHelper()
    {
    }

    
    public static JNIHelper getInstance()
    {
        synchronized(JNIHelper.class)
        {
            if(instance == null)
            {
                instance = new JNIHelper();
            }
        }

        return instance;
    }
    
    public static void main(String[] args)
	{
		getInstance().exec("pwd");
	}
}


2.通过jdk自带的javah命令生成c头文件com_pracbiz_JNIHelper.h

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

#ifndef _Included_com_pracbiz_JNIHelper
#define _Included_com_pracbiz_JNIHelper
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_pracbiz_JNIHelper
 * Method:    exec
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_pracbiz_JNIHelper_exec
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif


3.编写c++文件,实现头文件中的方法com_pracbiz_JNIHelper.cpp

#include   "com_pracbiz_JNIHelper.h"
#include <string.h>
#include <errno.h>
#include <iostream>
#include <cstdlib>
#include <string>
#include <iomanip>

using namespace std;

JNIEXPORT jstring JNICALL Java_com_pracbiz_JNIHelper_exec
(JNIEnv *env, jobject obj, jstring input)
{
    
    std::string result;
    std::string cmd;

    FILE *fstream=NULL;
    char buff[1024]="";

    char const *str = (char *)env->GetStringUTFChars(input, NULL);
    char const *ext = " 2>&1";

    cmd.append(str);
    cmd.append(ext);

    
    memset(buff,0,sizeof(buff));
    if(NULL==(fstream=popen(cmd.c_str(),"r")))
    {
        fprintf(stderr,"execute command failed: %s",strerror(errno));
        env->ReleaseStringUTFChars(input, str);
        return env->NewStringUTF("-1");
    }
    

    env->ReleaseStringUTFChars(input, str);

    while (NULL!=fgets(buff, sizeof(buff), fstream))
    {
        result.append(buff);
    }
    if (fstream != NULL)
    {
        pclose(fstream);
    }
    
    return env->NewStringUTF(result.c_str());
    
}

int main()
{
    return 0;
};


4.生成对应的jni可执行文件,注意命名格式,linux结尾为.so, mac os结尾为.jnilib
linux:
gcc -Wall -fPIC  -I./ -I/opt/jdk1.6.0_32/include -I/opt/jdk1.6.0_32/include/linux -shared -o libJNI.so com_pracbiz_JNIHelper.cpp -lstdc++

mac os:
gcc -Wall -fPIC  -I./ -I/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers -shared -o libJNI.jnilib com_pracbiz_JNIHelper.cpp -lstdc++

-l是编译时的路径参数,编译JNI文件需要两个java提供的库文件,jni.h和jni_md.h,对于linux, jni.h在opt/jdk1.6.0_32/include, jni_md.h存在/opt/jdk1.6.0_32/include/linux, 对于mac os来说,这两个文件都在 /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers目录下,不同的linux发行版以及不同的jdk版本可能位置会有所不同,这个在编译之前自己去确认下两个文件的路径。

5.文件生成好以后需要放到java.library.path,这样jvm才能加载到,那这个目录是什么呢,通过System.getProperty("java.library.path")方法就可以得到.
或者可以通过-Djava.library.path指定也行,下面会讲到。

6.应用很简单,写个TestJni.java,我是写在com.pracbiz.b2bportal.base.action包下面的.

system.out.println(JNIHelper.getInstance().exec("ls -la"));


以linux平台为例,如果so文件没有放到java.library.lib下,则运行时通过-Djava.library.path指定.so文件的路径
java   -Djava.library.path=/home/oyl-admin/b2bportal/EC-Portal/branches/fp-phase2-client/web/WEB-INF/classes  com.pracbiz.b2bportal.base.action.TestJni
如果已经放到java.library.lib下,则直接运行
java com.pracbiz.b2bportal.base.action.TestJni
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics