Java调用不支持JNI的Linux so文件

基本思路:A.so(支持JNI)、B.so(不支持JNI),Java -> A.so -> B.so

1、java代码
package com.abc.util;
public class AuthCheck {
	static {
		System.loadLibrary("socall");
	}

	public native static long valid();

	public static void main(String[] args) {
		AuthCheck test = new AuthCheck();
		System.out.println(test.valid());
	}
}
2、编译java代码
进入到com/abc/util下
javac AuthCheck.java
3、生成.h文件
返回到com的上一级目录
javah -jni -classpath /home/xiao/JNITest com.abc.util.AuthCheck
会生成com_abc_util_AuthCheck.h
4、编写c文件socall.c
#include    
#include 
#include    
#include "com_abc_util_AuthCheck.h"

JNIEXPORT jlong JNICALL Java_com_abc_util_AuthCheck_valid(JNIEnv *env, jclass jc)
{
   long (*myadd)();
   void *handle;   
      
   handle=dlopen("./libnojni.so",RTLD_LAZY);//open lib file   
   if(!handle){
	   fprintf(stderr, "%s\n", dlerror());
	   exit(EXIT_FAILURE);
   }

   dlerror();

   myadd=dlsym(handle,"Valid"); // libnojni.so中有函数long  Valid()
   
   long result=myadd();   
   dlclose(handle);   
   //printf("%d\n",result); 
   return result;
}
注意:如果libnojni.so是32位的,而你的Linux是64位的,那么以上代码运行会报错。需要统一为32或64
5、生成so文件
gcc -I/usr/java/jdk1.7.0_80/include/linux -I/usr/java/jdk1.7.0_80/include -fPIC -shared -o libsocall.so socall.c 
6、把两个so文件拷贝到jdk
cp /home/xiao/JNITest/libsocall.so libnojni.so /usr/java/jdk1.7.0_80/jre/lib/amd64/
7、返回/home/xiao/JNITest下

java com.abc.util.AuthCheck

8、web应用调用so

web应用一般在web容器里,例如tomcat。此时再次调用,会出现异常:无法打开共享对象文件: 没有那个文件或目录

解决办法就是:把libsocall.so、libnojni.so放到web应用有权限访问并执行的目录下,例如tomcat你用abc用户启动,那么so文件就可以放到/home/abc下。

然后System.loadLibrary("socall");改为System.load("/home/abc/libsocall.so");然后重启tomcat

设置web应用的java.library.path应该修改tomcat的jvm参数,编辑apache-tomcat-7.0.64/bin/catalina.sh,找到# OS specific support,在此行上面加上以下内容

export JAVA_OPTS="-Djava.library.path=你so文件的存放路径",然后java调用so可以使用System.loadLibrary("socall")

==================================================================================

以下转自http://blog.csdn.net/ring0hx/article/details/3242245,内容不完全正确,仅供参考,以实践为准

System.load 和 System.loadLibrary详解

1.它们都可以用来装载库文件,不论是JNI库文件还是非JNI库文件。在任何本地方法被调用之前必须先用这个两个方法之一把相应的JNI库文件装载。

2.System.load 参数为库文件的绝对路径,可以是任意路径。
例如你可以这样载入一个windows平台下JNI库文件:
System.load("C://Documents and Settings//TestJNI.dll");。

3. System.loadLibrary 参数为库文件名,不包含库文件的扩展名。
例如你可以这样载入一个windows平台下JNI库文件
System. loadLibrary ("TestJNI");

这里,TestJNI.dll 必须是在java.library.path这一jvm变量所指向的路径中。
可以通过如下方法来获得该变量的值:
System.getProperty("java.library.path");
默认情况下,在Windows平台下,该值包含如下位置:
1)和jre相关的一些目录
2)程序当前目录
3)Windows目录
4)系统目录(system32)
5)系统环境变量path指定目录

4.如果你要载入的库文件静态链接到其它动态链接库,例如TestJNI.dll 静态链接到dependency.dll, 那么你必须注意:
1)如果你选择
System.load("C://Documents and Settings// TestJNI.dll");
那么即使你把dependency.dll同样放在C://Documents and Settings//下,load还是会因为找不到依赖的dll而失败。因为jvm在载入TestJNI.dll会先去载入TestJNI.dll所依赖的库文件dependency.dll,而dependency.dll并不位于java.library.path所指定的目录下,所以jvm找不到dependency.dll。
你有两个方法解决这个问题:一是把C://Documents and Settings//加入到java.library.path的路径中,例如加入到系统的path中。二是先调用
System.load("C://Documents and Settings// dependency.dll"); 让jvm先载入dependency.dll,然后再调用System.load("C://Documents and Settings// TestJNI.dll");
2)如果你选择
System. loadLibrary ("TestJNI");
那么你只要把dependency.dll放在任何java.library.path包含的路径中即可,当然也包括和TestJNI.dll相同的目录。

你可能感兴趣的:(linux,java)