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。(不是本次讨论重点)
System.load("/opt/costso/feeso/ext/calcfee.so");
public native static int Feeinit();
public native static CostServiceOutputBean calcFee(CostServiceInputBean a);
public native static int FeeEnd();
DoCostServiceSo.calcFee(bean);
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,欢迎大家补充交流!