前面系统研究了 JNI 的相关操作,下面就来小试牛刀,做一个实际的练习。
记得去年我曾经用 C 语言写过一个 PHP 的 md5 扩展函数,那么今天就花一点点时间用 JNI 来实现一遍吧。
不过这里可要提前声明了,虽然是实现 md5 函数,但是这里并不会从头写 md5 算法,而是投机取巧使用到了 linux 内核提供的crypto
库。
废话不多说,首先来写一个 Java 类
MyString.java
1public class MyString {
2 static {
3 System.loadLibrary("mymd5");
4 }
5
6 private String value;
7
8 public native String md5();
9
10 public MyString(String value) {
11 this.value = value;
12 }
13}
然后生成头文件,并实现 c 代码:
1#include <jni.h>
2#include <openssl/md5.h>
3#include <string.h>
4
5JNIEXPORT jstring JNICALL Java_MyString_md5(JNIEnv *env, jobject obj) {
6 jclass thisClass = (*env)->GetObjectClass(env, obj);
7 jfieldID fidValue = (*env)->GetFieldID(env, thisClass, "value", "Ljava/lang/String;");
8 if (NULL == fidValue) {
9 return NULL;
10 }
11 jstring value = (*env)->GetObjectField(env, obj, fidValue);
12
13 const unsigned char *data = (*env)->GetStringUTFChars(env, value, NULL);
14 MD5_CTX ctx;
15 unsigned char md[16];
16 char buf[33]= {'\0'};
17 char tmp[3]= {'\0'};
18 int i;
19 MD5_Init(&ctx);
20 MD5_Update(&ctx,data,strlen((char *)data));
21 MD5_Final(md,&ctx);
22
23 for( i=0; i<16; i++ ) {
24 sprintf(tmp,"%02X",md[i]);
25 strcat(buf,tmp);
26 }
27
28 value = (*env)->NewStringUTF(env, buf);
29 return value;
30}
至此代码平淡无奇,也没什么好解释的,不过需要注意的是编译成动态链接库的部分,由于这里依赖到了其他的动态链接库,所以编译参数需要使用-L{path} -l{libname}
来显示的指明依赖库的路径和库名
1gcc -fPIC -shared -I /opt/app/java/include/ -I /opt/app/java/include/linux/ -I /usr/include/openssl/ -L/usr/lib/x86_64-linux-gnu/ MyString.c -lcrypto -o libmymd5.so
这样就编译好了,然后我们写一个测试类
1public class Test {
2 public static void main(String[] args) {
3 MyString s = new MyString("liubang");
4 System.out.println(s.md5());
5 }
6}
编译并运行:
1ubuntu@vm-911:~/workspace/java/jni/demo4$ java -Djava.library.path=. Test
2D67DF7EAE3E651E9DA077E9423C7A9B6
enjoy!
评论