JAVA调用SO库的示意图

JNI方式调用SO库

 

关于JNI的API已经放在:供使用JNI时参考

  • 首先知道

用JNI调用别人提供的.so文件,现在要Windows系统下测试运行情况,提出了核心问题:怎么在Windows下使用eclipse java程序调用.so文件?上网查全是在Linux下调.so或者在Windows下调.dll文件,跟我的情况不匹配。以下是我的思考与总结

这个问题的本质其实在于JNI的缺点—-破坏了Java的跨平台性。虽然Java项目是跨平台的,可以轻易的从Linux移植到Windows,但是C/C++是不跨平台的。.dll文件和.so文件在调用时是需要编译链接的,这就要求系统必须要有相对应的环境,因此是不能在Windows下调.so文件的,也不能在Linux下调.dll文件。因此从理论上来讲,这个问题只有后面讲的两个笨方法,而没有太完美的解决办法(我查到有说用工具可以在Windows下生成.so文件的,但也没有讲清楚能不能运行,如果有更好的办法请大神留言多多指教)。所以解决思路就是要么换开发环境,要么生成对应于.so文件的.dll文件。如果前面两种都不好实现的话,还有一种就是在Windows下进行调用so库,我称之为“盲开发”(不推荐,实在没办法再用)——假设当前是在Linux环境下进行开发,无非就是不好Debug罢了。

两种常规解决方式(两个笨方法):

1将.so文件对应的C/C++源码拿到Windows下编译链接,生成.dll文件,替换原来的.so文件即可。(如果拿不到源码就没办法了)

2、将开发环境换成Linux下的,这样一定可以成功调用.so文件。

 

总结: JNI使得Java可以运行本地方法或接口,但也破坏了Java的跨平台性。所以除了以下三种情况外,最好不要用JNI:

1、项目中的某个部分的算法对效率有着很严的要求,需要使用偏底层的C/C++来提高效率

2、现有的API不支持项目中的一些环境,需要自己在底层实现

3、项目很在意资源利用,不愿意跨进程,不愿意增加时间、内存开销

而非必须条件下可以用跨进程(如用TCP/IP来调用本地的函数)或者跨机器(如部署成分布式)来代替JNI。(不是本次讨论重点)

 

  • JAVA使用JNI调用so库的大概过程

 

 

  • 使用过程

JAVA中需要做的:

  1. 在JAVA源码中加载so库,注意该地址一定要能找到该so库

System.load("/opt/costso/feeso/ext/calcfee.so");

 

  1. 声明需要调用C++/C里面的函数为JAVA本地方法,注意关键字native的使用

public native static int Feeinit();

 

public native static CostServiceOutputBean calcFee(CostServiceInputBean a);

 

public native static int FeeEnd();

 

  1. 在JAVA中相应位置根据需要调用即可

DoCostServiceSo.calcFee(bean);

 

C++/C中需要做的(Linux环境下):

  1. 拿到JAVA编译后的.class文件
  2. 使用命令 javah xxx.xxx.xxx.class,得到.h文件
  3. 根据2生成的.h文件自己写.c文件进行实现C++/C中的业务功能。注意严格按照JNI的使用规范——参考API文档
  4. 使用编译命令将编写好的.c文件生成.so文件
  5. 完成

 

 

 

  • Linux下编译命令

1、g++ -g -c -o parm_delv_v3.o parm_delv_v3.c

2、g++ -g  parm_delv_v3.o -o parm_delv_v3 -L/usr/lib/mysql -lmysqlclient ../comm.o ../config.o ../xml/tinystr.o ../xml/tinyxml.o ../xml/tinyxmlerror.o ../xml/tinyxmlparser.o

3、g++ -g -o test test.c -ldl

4、g++ -fPIC -shared -o calcfee.so parm_delv_v3.o ../comm.o ../config.o ../xml/tinystr.o ../xml/tinyxml.o ../xml/tinyxmlerror.o ../xml/tinyxmlparser.o -Xlinker --unresolved-symbols=ignore-in-shared-libs

5、g++ -fPIC -shared -o calcfee.so parm_delv_v3.o  -L/usr/lib/mysql -lmysqlclient -L/home/coder/jifei -L/home/coder/jifei/xml comm.o config.o tinystr.o tinyxml.o tinyxmlerror.o tinyxmlparser.o -Xlinker --unresolved-symbols=ignore-in-shared-libs

 

 

本次主要用到以下三个编译命令:

1、Javah  com.project.communication.action.CommunicationAction 

 

在运行的.c路径下执行下面两个编译命令:   

2、g++ -g -c -o parm_delv_v3.o -I/usr/java/jdk1.8.0_181/include  -I/usr/java/jdk1.8.0_181/include/linux parm_delv_v3.c

3、g++ -fPIC -shared -o calcfee.so parm_delv_v3.o ../comm.o ../config.o ../xml/tinystr.o ../xml/tinyxml.o ../xml/tinyxmlerror.o ../xml/tinyxmlparser.o -Xlinker --unresolved-symbols=ignore-in-shared-libs

 

  • 最后说明

在阅读demo的时候,主要查看如下JNI规范的代码:使用关键字JNI开头的

 

如:JNIEXPORT jint JNICALL Java_com_project_communication_action_DoCostServiceSo_Feeinit(JNIEnv *env, jobject jc){

return Feeinit();

}

 

 

 

更多复杂的功能还需读者根据JNI的API自己体会开发。

如有疑问请联系作者。QQ:942297338,欢迎大家补充交流!

JAVA调用SO库的示意图_第1张图片

你可能感兴趣的:(JAVA调用SO库的示意图)