当使用到JNI的时候,基本可以肯定Java的平台移植性注定减弱,接下来记录一次使用Java JNI开发的经历。

关于Java JNI的相关资料参见:

下面是使用JNI常见三种场景:

1.在Java应用中标准Java类库不支持平台相关的特性

2.已经存在用其它语言写好的类库,希望通过Java JNI类访问

3.需要使用低级语言(如汇编)来实现时效性要求很高的一小部分代码

这次使用JNI属于第2中场景,由于加解密库使用C来实现的,而在Java应用中使用到其加密后的密文数据,所以解密部分需要此库。

在1和3这两种场景下使用JNI做法相对容易一些,通常先定义好本地方法,然后通过javah生成头文件,接着用其它语言(如C)来实现相应的功能,而2中场景则需要做一些简单的适配,因为类库已经存在,而在Java中定义好的本地方法并不能直接对应类库的具体实现,所以得通过调用已存在的类库中的方法来实现本地方法。

在开始之前有一个坑先看看:

本地编译好的动态库头信息:

[ enc]$ readelf -a libfdsi.so

ELF Header:

Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00

Class:                             ELF64

Data:                              2's complement, little endian *******

Version:                           1 (current)

OS/ABI:                            UNIX - System V

ABI Version:                       0

Type:                              DYN (Shared object file)

Machine:                           Advanced Micro Devices X86-64

提供方静态库信息:

ELF Header:

Magic:   7f 45 4c 46 02 02 01 00 00 00 00 00 00 00 00 00

Class:                             ELF64

Data:                              2's complement, big endian

Version:                           1 (current)

OS/ABI:                            UNIX - System V

ABI Version:                       0

Type:                              REL (Relocatable file)

Machine:                           PowerPC64

通过对比应该很清楚了,数据存储模式不同。这里需要明确的是环境一致性很重要。

接下来来从头到尾实现一个Java调用C的一个解密方法。

1.定义Java的本地方法(DataDecryt.java)

package com.cto;

public class DataDecrypt{

native public static String decrypt(String data);

}

2.通过javah命令生成头文件(dd.h)

./javah -classpath . -jni -o dd.h com.cto.DataDecrypt

/* DO NOT EDIT THIS FILE - it is machine generated */

#include

/* Header for class com_cto_DataDecrypt */

#ifndef _Included_com_cto_DataDecrypt

#define _Included_com_cto_DataDecrypt

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class:     com_cto_DataDecrypt

* Method:    decrypt

* Signature: (Ljava/lang/String;)Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_com_cto_DataDecrypt_decrypt

(JNIEnv *, jclass, jstring);

#ifdef __cplusplus

}

#endif

#endif

3.定义使用静态库中的方法的头文件(dec.h)

#ifndef __DEC__

#define _DEC__

#ifdef __cplusplus

extern "C"{

#endif

int ts_comm_dec(const char* in , int inlen, char* out, int* outlen);

#ifdef __cplusplus

}

#endif

#endif

ts_comm_dec方法即为已经实现了的解密方法。

4.创建实现dd.h头文件方法的cto.c文件,cto.c中将调用ts_common_dec方法

#include

#include

#include "dec.h"

#include "dd.h"

//about JNI http://doc.oracle.com/javase/1.5.0/docs/guide/jni/spec/functions.html

JNIEXPORT jstring JNICALL Java_com_cto_DataDecrypt_decrypt

(JNIEnv *env, jclass jc, jstring data){

char out_str[48];

const char *enc_str = (*env)->GetStringUTFChars(env, data, 0);

const jsize  enc_len = (*env)->GetStringUTFLength(env, data);

int  out_len = sizeof(out_str);

ts_comm_dec(enc_str, enc_len, out_str, &out_len);

jstring plain_text = (*env)->NewStringUTF(env, out_str);

(*env)->ReleaseStringUTFChars(env, data, enc_str);

return plain_text;

}

5.编写测试用例(TestDataDecrypt.java)

这里加载的类库cto即为libcto.so。关于动态库静态库命名规则可百度之。

package com.cto;

import com.cto.DataDecrypt;

public class TestDataDecrypt{

static {

System.loadLibrary("cto");

}

public static void main(String [] args){

String plainText= DataDecrypt.decrypt(args[0]);

System.out.println(plainText);

System.out.println("解密之后的长度是:"+plainText.length());

}

}

6.编译动态库

gcc cto.c -shared -fPIC -lstdc++  -I~/soft/jdk1.6.0_45/include -I~/soft/jdk1.6.0_45/include/linux -I~/native/enc  libtsbase.a  -o libcto.so

7.运行测试

./java -cp . -Djava.library.path=. com.cto.TestDataDecrypt Qt96BsMOKGjZ0oiqqhRqcA==

13********1

解密之后的长度是:11

解密后的结果和预期一致。

8.需要注意的事项

命令:javac java javah是同一版本,有时候可能系统中有多个版本的JDK

权限:从其它地方复制的文件,需要确认读写执行权限

其它:即便按照文中方法来,同样会遇到各种各样的问题,需要多多查看和发现

java jni开发_Java JNI开发实践记录相关推荐

  1. java web试题_Java web开发经典面试题汇总(内附答案详解)

    原标题:Java web开发经典面试题汇总(内附答案详解) 1.说出Servlet 的生命周期,并说出Servlet 和CGI 的区别? 答:Web 容器加载Servlet 并将其实例化后,Servl ...

  2. java 日志设计_Java日志设计实践(3) - 开发篇

    1.选择恰当的日志级别 2.输出明确的提示文字和充分的现场信息 3.输出内容一行搞定,不要换行 4.其他 1.选择恰当的日志级别 选择日志级别时需要遵循一些通用规范,不可随意定义 log4j的日志级别 ...

  3. java项目流程_Java项目开发全流程实践

    文章导读 [项目遵循需求分析.程序设计.编码.测试.运行标准开发过程, 从分析项目问题入手,提出解决方案,应用对象建模工具UML设计系统,依据设计文档进行编码.] 问题描述:实现一个简单的四则运算器. ...

  4. java 托盘开发_java托盘开发界面记录

    设置对话框为圆角: //首先选择设置 JFrame.setDefaultLookAndFeelDecorated(true); JDialog.setDefaultLookAndFeelDecorat ...

  5. java自动化开发_Java自动化开发指南

    一.背景 在Java web开发中,虽然Spring boot已经帮助我们简化了很多工作,但项目中庞杂的业务仍然需要自己去编写较多的 entity,vo,Mapper,Service, Control ...

  6. java 记事本 新建_java记事本开发

    今天我想要分享的是一个用java写的一个记事本程序.我知道现在市面上有各种各样的记事本了,但是我发现有的写的功能不够完善,或者是代码层次结构不够清晰,有的甚至看了之后云里雾里的,有的还不乏了非常明显的 ...

  7. web开发的java语言步骤_java web开发入门一(servlet和jsp)基于eclispe

    servlet 用java语言开发动态资源网站的技术,在doGet方法中拼接显示html,在doPost方法中提交数据.类似于.net的ashx技术. servlet生成的class文件存放在tomc ...

  8. java系统教程_Java 教程(开发环境配置+基础语法)

    Java 开发环境配置 在本章节中我们将为大家介绍如何搭建Java开发环境. window系统安装java 下载JDK 首先我们需要下载java开发工具包JDK,下载地址:http://www.ora ...

  9. java电话计费系统_java 连接数据库开发的电话计费管理系统

    [实例简介] 这是java连接数据库 sql 2000 开发的电话计费管理系统 里面运用的还是比较方便的虽然有一点小问题 [实例截图] [核心代码] 电话计费系统 └── 电话计费系统 ├── all ...

最新文章

  1. 通过ping命令测试主机与虚拟机之间是否连通
  2. 网易云信携手小天才Z6手表,让安全“看得见”
  3. c语言做贪吃蛇vs2015,熬书几个月,终于编出简易的贪吃蛇了,VS2013
  4. 自适应 幻灯片代码 app_低成本0基础开发app之开发首页幻灯片接口
  5. Spark(Core)
  6. 产品经理应该看什么书?
  7. CAD随机圆形颗粒插件
  8. 计算机视觉和模式识别领域企业论坛,第三届中国模式识别与计算机视觉大会(PRCV 2020)圆满举办...
  9. C# 打开CMD窗口并执行CMD 指令
  10. netware php_Linux中NetWare客户端简易安装说明(转)
  11. 【SpringBoot整合NoSql】-----ElasticSearch的安装与操作篇
  12. K.dot和K.batch_dot
  13. 大国的崛起:第二集:小国大业 荷兰
  14. 序列回帖与multi-mapped reads的处理
  15. 身份证男女识别---非线性问题01
  16. 《神经网络与深度学习》—学习笔记
  17. 1号店详情页(共5页)
  18. 计算机程序 申请专利,计算机程序能申请专利吗
  19. Audio的framecount、framesize、sampleRate计算关系
  20. git bash里ln -s

热门文章

  1. 什么时候需要使用cqrs_在CQRS读取模型中使用Hibernate进行快速开发
  2. jcache_随机JCache内容:多个提供程序和JMX Bean
  3. 终端查看命令有哪些功能命令_从命令式功能到纯粹功能式功能,再返回:Monads与范围内的延续...
  4. junit junit_使用junit做其他事情
  5. 硒测试中所需的功能和示例
  6. 使用Hibernate和Spring构建Java Web应用程序
  7. mockito java_使用Mockito在Java中进行模拟入门
  8. java pojo使用_在POJO中使用ThreadLocal进行Java嵌套事务
  9. 谓词::不适合Java
  10. jvm 性能_JVM性能魔术