您的位置:首页 > 运维架构 > Linux

Linux平台下使用JNI

2011-07-29 21:06 344 查看
1首先创建一个简单的java类:

publicclassHello

{

static

{

try

{

//此处即为本地方法所在链接库名

System.loadLibrary("hello");

}

catch(UnsatisfiedLinkErrore)

{

System.err.println("Cannotloadhellolibrary:\n"+

e.toString());

}

}

publicHello()

{

}

//声明的本地方法

publicnativevoidSayHello(StringstrName);

}

这里有个地方要注意,就是这个类最好不要加包信息。因为类在某个包下面,使用javah命令生成*.h头文件的时候会不一样,比如在test包下,就会生成test_Hello.h,而且在jni调用的时候,也有区别,为了方便起见,我们这里就不加包了,免得麻烦,:)

然后,编译得到Hello.class

2生成Hello.h

使用命令:javahHello

这里有一点要注意,如果这个命令报错,有可能是因为你没有当前路径到设置环境变量classpath中,所以:

javah-classpath"."Hello.class

这样写就OK了,后面也许还会碰到类似的环境变量问题。

3在与Hello.h相同的路径下创建一个CPP文件Hello.cpp。内容如下:

#include"Hello.h"
JNIEXPORTvoidJNICALLJava_Hello_SayHello(JNIEnv*env,jobjectarg,jstringinstring)
{
constchar*str=env->GetStringUTFChars(instring,JNI_FALSE);
printf("Hello,%s\n",str);
env->ReleaseStringUTFChars(instring,str);
return;
}

这个Hello.cpp的代码,跟IBM的例子略有不同,详细原因大家自己去查查jni.h

4.编译生成共享库

a.编译命令,生成Hello.o

g++-I/usr/lib/jvm/java-6-sun-1.6.0.03/include-I/usr/lib/jvm/java-6-sun-1.6.0.03/include/linux-fPIC-cHello.cpp

b.生成动态库文件,libhello.so.1.0

g++-shared-Wl,-soname,libhello.so.1-olibhello.so.1.0Hello.o

这里的2个命令也跟IBM文章的例子有所不同。因为使用gcc编译得到动态库,在jni调用的时候,某些情况会有异常,所以这里改用g++。

接下来将生成的共享库拷贝为标准文件名
[code]cplibhello.so.1.0libhello.so

最后通知动态链接程序此共享文件的路径。
exportLD_LIBRARY_PATH='pwd':$LD_LIBRARY_PATH


这里用
export加入共享文件的路径,有时候会有点问题,比如:环境变量不会马上更新等等。

还有一个办法,就是直接将libhello.so拷贝到/usr/lib或者/lib等系统库目录下



5.编写一个简单的Java程序来测试我们的本地方法。

将如下源码存为ToSay.java:
importHello;
importjava.util.*;
publicclassToSay
{
publicstaticvoidmain(Stringargv[])
{
ToSaysay=newToSay();
}
publicToSay()
{
Helloh=newHello();
//调用本地方法向John问好
h.SayHello("John");
}
}
用javac编译ToSay.java,生成ToSay.class
向执行普通Java程序一样使用javaToSay,我们会看到在屏幕上出现Hello,John。
6以下是IBM的文章中的建议:
应用中注意事项
1.如果可以通过TCP/IP实现Java代码与本地C/C++代码的交互工作,那么最好不使用以上提到的JNI的方式,因为一次JNI调用非常耗时,大概要花0.5~1个毫秒。
2.在一个Applet应用中,不要使用JNI。因为在applet中可能引发安全异常。
3.将所有本地方法都封装在单个类中,这个类调用单个DLL。对于每种目标操作系统,都可以用特定于适当平台的版本替换这个DLL。这样就可以将本地代码的影响减至最小,并有助于将以后所需的移植问题包含在内。
4.本地方法要简单。尽量将生成的DLL对任何第三方运行时DLL的依赖减到最小。使本地方法尽量独立,以将加载DLL和应用程序所需的开销减到最小。如果必须要运行时DLL,则应随应用程序一起提供它们。
5.本地代码运行时,没有有效地防数组越界错误、错误指针引用带来的间接错误等。所以必须保证保证本地代码的稳定性,因为,丝毫的错误都可能导致Java虚拟机崩溃。

7思考的问题
我以前一直在想,如果我使用JNI来调用C/C++实现的socket通信库,会不会比java自己的nio性能要好?
貌似IBM的兄弟的回答是否定的。

也有人不同意这个意见,说因为Java代码与本地C/C++代码的交互工作不是那么频繁,即使浪费0.5~1个毫秒,也没什么关系。
貌似BEA的weblogic(weblogic9以后的版本)就采用这个做法。

以后有机会我就来做个试验,测试一下,呵呵。
当然,有兄弟已经测试过了,来告诉我,就最好啦,哈哈!!!
[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: