Linux平台下使用JNI

1 首先创建一个简单的java类:

public class Hello
{
 static
 {
  try
  {
//此处即为本地方法所在链接库名
   System.loadLibrary("hello");
  }
  catch(UnsatisfiedLinkError e)
  {
   System.err.println( "Cannot load hello library:\n " +
                                e.toString() );
  }
 }
 public Hello()
 {
 }
//声明的本地方法
  public native void SayHello(String strName);
}

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

然后,编译得到Hello.class

2 生成 Hello.h

  使用命令:javah Hello

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

  javah -classpath"." Hello.class

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

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

#include "Hello.h"
JNIEXPORT void JNICALL Java_Hello_SayHello  (JNIEnv * env, jobject arg, jstring instring)
{
    const char *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 -c Hello.cpp
b.生成动态库文件,libhello.so.1.0
g++ -shared -Wl,-soname,libhello.so.1 -o libhello.so.1.0 Hello.o
这里的2个命令也跟IBM文章的例子有所不同。因为使用gcc编译得到动态库,在jni调用的时候,某些情况会有异常,所以这里改用g++。

接下来将生成的共享库拷贝为标准文件名

cp libhello.so.1.0 libhello.so

最后通知动态链接程序此共享文件的路径。

export LD_LIBRARY_PATH='pwd':$LD_LIBRARY_PATH

 

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

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

 

 

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

将如下源码存为ToSay.java:

import Hello;
import java.util.*;
public class ToSay
{
	public static void main(String argv[])
	{
		ToSay say = new ToSay();
	}
	public ToSay()
	{
		Hello h = new Hello();
		//调用本地方法向John问好
		h.SayHello("John");			
	}
}
用javac编译ToSay.java,生成ToSay.class 
向执行普通Java程序一样使用java ToSay,我们会看到在屏幕上出现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(weblogic 9以后的版本)就采用这个做法。

 

以后有机会我就来做个试验,测试一下,呵呵。

当然,有兄弟已经测试过了,来告诉我,就最好啦,哈哈!!!


你可能感兴趣的:(java,linux,weblogic,jni,dll,平台)