Java—JNI的使用

Java—JNI的使用

    最近因公司业务需求,需要将Java代码中的一部分核心的算法使用C++/C编写,生成.dll(windows使用)或.so(linux或unix使用)文件,这样可以起到加密的作用.

    首先,我们需要在Java代码中加载类库(就是.dll或.so文件),使用如下方式(javaCallcpp是你类库的名称):
    System.loadLibrary("javaCallcpp");
    之后,我们需要将所要加密的方法使用native关键字定义,如:
    public native byte[] GET_KEY(byte[] AES_DEF_KEYS, byte[] QR_RAND);
    之后,我们就可以使用javah命令来生成.h文件了,这里要注意几个问题.
    第一个是一般我们的Java类都会引用其他的类,可能网上直接查到的一些命令无法运行,所以在命令中要加上classpath的路径.
    第二个是编码问题.
    这里我是这样做的,我直接在java代码的classpath路径下运行如下命令:
    javah -encoding utf-8 -classpath . 包名.类名(就是你有native标记方法那个类的路径)
    之后,你就会看到这个路径下生成了一个.h文件,这个就是之后C++/C中需要使用的文件.
    这个时候我们就要开始编写C++/C项目了,我这里使用的IDE是VS 2010,这里有个问题主要注意,我是在windows环境下进行开发测试,博主之前使用了VC++6.0,但是编译出来的.dll文件在java代码中不能使用,因为编译出来的是32位的,但是我得JDK是64位的(可能和JDK位数或者系统位数有关系,这里博主只是猜测和JDK位数有关),所以java代码无法执行,会出现一个位数异常.
    使用VS 2010也是因为VS 2010可以编译出64位的.dll文件.


    我们使用VS 2010创建一个WIN32位的项目(VS里面是这么叫的,之后可以设置成64位)

    接下来我们把项目设置为64位编译,在生成 -> 配置管理器,然后你就可以看到活动解决方案平台,换成64位就好了。

这里有一点很重要的地方需要注意,可能你做完之后Java代码也可以成功调用.dll文件了,然后你就高兴的把这个东西发给别人去运行,这个时候就有问题了,如果另一个人的电脑上没有装VS 2010,他是跑不了的,为什么呢?根据我的推测,是因为VS 2010默认编译的时候引入了其他的一些运行库,但是别人电脑上没有装VS 2010,那他就没法运行,因为我不会c++/c,所以我也只是推测是这样的原因.解决方案如下:

右键项目,选择属性,在配置属性 -> c/c++ -> 代码生成中将运行库那一行的东西都删掉,再进行编译生成的dll文件,应该就没问题了.该问题只会出现在windows系统下,因为.so是由linux/unix的g++或gcc命令就行编译,不会出现该问题.

    继续上面说,配置好之后,我们要去你的JDK中找两个文件,在JDK目录下的include下有个jni.h,将该文件复制到项目下,然后打开该目录下的win32文件夹,找到jni_md.h文件,同样的,将该文件复制到项目下.

    这个时候,我们总共有3个.h文件,之前用javah命令生成的,还有jni.h和jni_md.h,我们要对这三个文件的#include做一些修改,将这三个文件中互相引入的#include中的尖括号改为双引号,例如在javah生成的.h文件中,有#include <jni.h> 修改为#include "jni.h",这样就代表我引入当前目录下的这个jni.h文件.

    然后,我们在.cpp文件中引入javah生成的那个.h头文件,将javah生成的.h文件中的方法定义复制到cpp中,然后对其进行你想要的实现.之后编译之后,生成.dll文件,就大功告成了.一般dll文件是要放在你java.library.path路径下,如果你不知道你的这个路径在哪,请自己输出到控制台看看.
    System.getProperty("java.library.path");
    这个时候在dll文件就搞定了,但是一般来说,如果我们使用linux或者unix系统,dll文件是不能使用的,要使用so动态库.
    这个时候我们可以将你的.cpp和javah生成的文件复制到linux/unix的环境下,注意,这里我们依然需要jni.h和jni_md.h,但是我们不能将之前使用的jni.h和jni_md.h直接拿到linux/unix环境下使用,我们需要使用linux版本JDK中的jni.h和jni_md.h,这样才可以.然后将这几个文件都放在同一个文件夹下,执行编译命令:
    gcc -fPIC  -shared -o lib包名.so 文件名.c
    上面是c语言的,如果你用的是c++,就需要使用
    g++ -fPIC  -shared -o lib包名.so 文件名.cpp
    这样就好了,这里有一点,你生成出来的.so文件前面是有一个lib前缀的,这个是linux的默认用法,你在java代码里还是直接引入包名就好了,不需要在前面加上lib.

    这就是我这次做这个加密的具体做法,因为对操作系统的不熟悉,不会使用c++,中间还是踩了不少坑的.
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xingtingshu/article/details/51506477
文章标签: java jni
个人分类: Java
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭