JNI原理1

在某些Java的忠实支持者眼中,JNI(Java Native Interface)是难登大雅之堂的,因为JNI生来便仿佛和Java“Write Once, Run Everywhere”的宗旨相背离。其实这是一种偏见,因为只要承认Java在执行一些关键业务时在实时性方面的不足,只要承认Java在与底层交互方面存在诸多壁垒,JNI便有其存在的必要。况且,更理性地看待这个问题:Java最初诞生的机缘在于网络的兴起,而后来流行的原因则在于掌握企业计算命脉的几个关键厂商的推波助澜,这一切都决定了Java擅长于企业应用开发,而在实时应用和桌面应用领域的不足。正如同无人能够抹煞Java的安全性和组件化,其他语言自有其存在和发展的理由。JNI正是为Java和其他语言之间的互操作打开了方便之门,可以说,这对Java团队来说是借力打力的好事!

另一种顾虑来自于“耦合度”方面,部分人认为实现异构系统、异质语言之间的互操作途径有很多种,未必需要基于JNI重写系统。笔者认为:(1)系统的耦合度首先不在于技术路线的选型,而在于设计和规划:即使采用SOA(面向服务的体系结构)和ESB(企业服务总线),一个不良的设计,很可能让实施效果大打折扣;(2)应用系统的需求是多方面的,耦合度只是其中之一,而在耦合度之外,还有性能和可靠性等指标:我们不能接受,也难以想象每一次原本可以通过本地调用完成的任务,都要发起一次进程间调用。

本章主要内容包括:

¿  JNI原理

¿ 调用C程序

¿ 调用Delphi程序

本章首先介绍JNI原理,然后分别介绍两种JNI的应用场景:Java语言调用C程序、Java语言调用Delphi程序。

15.1  JNI原理

JNI是Java Native Interface(Java本地接口)的缩写。所谓本地接口,是相对运行在Java虚拟机“沙箱”中的Java程序而言的,指直接运行在操作系统之上,与操作系统直接交互的程序。从JDK 1.1开始,JNI规范成为Java平台的一部分,它允许Java程序和用其他语言编写的程序进行交互。JNI一开始是为了Java程序与本地已编译语言,尤其是C和C++的互操作而设计的,但是这并不意味着不能使用其他语言。

使用Java语言与本地已编译的代码交互,意味着丧失平台Java语言“Write Once, Run Everywhere”的可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。比如,使用一些旧的类库与硬件、操作系统进行交互,或者为了提高程序的性能。JNI规范保证了Java程序能够以尽量少的代码、尽可能相同的方式调用本地类库。

可以形象直观地把JNI看做是Java和本地应用程序的黏合剂。如图15-1所示,JNI规范成为沟通C语言类库及函数和Java对象之间的媒介。

图15-1  JNI原理

一般来说,使用100%纯Java语言编写程序仍然是首选目标,毕竟程序的可移植性和安全性是我们选择Java语言的初衷。概括起来,采用JNI调用本地程序接口的情况包括以下几个方面。

— 为了实现Java语言所不能实现的功能:例如关闭系统、获取CPU繁忙程度等。

— 为了获取更好的程序运行性能:和其他语言一样,Java程序运行的性能很大程度上取决于程序代码的编写质量,但是在一些实时性要求高的应用场合,以“半编译”形态出现的Java语言是难以胜任的,这时借助运行性能更佳的本地程序来完成这些关键任务更为合理。

— 为了保护历史投资:当然前提条件是程序的可移植性不是首要被看重的因素。企业应用开发成本往往是决定编码规模和开发周期的重要因素,当已经有一些使用传统语言编写的模块被证明能够良好地实现企业业务需求,为了缩短开发周期、降低开发成本,可能就需要考虑采用JNI调用这些旧模块。

基于Oracle数据库管理系统开发应用的读者应该不会陌生,Oracle提供的JDBC驱动程序分为两套,采用OCI(Oracle Call Interface)的本地调用类库和纯Java实现的驱动程序类库。采用前者的执行性能更好,而且因为Oracle在主流操作系统平台上提供的供调用的本地类库的调用形式完全相同,因此对应用开发人员而言,使用这套基于JNI原理的驱动程序类库几乎感受不到整个系统的可移植性受到了影响。

 

指出一点,使用Java虚拟机运行时Java LangRuntime调用外部进程不属于JNI的范畴。关于Java语言如何调用外部进程,请参考本书的第6章“输入输出综合”的有关内容。

在下一节中,我们将介绍使用JNI调用C程序的典型步骤。

http://book.youkuaiyun.com/bookfiles/606/10060619591.shtml

### JNI 的实现原理详解 JNIJava Native Interface)是一种编程框架,允许 Java 代码和其他语言编写的代码进行交互。以下是关于 JNI 实现原理的详细介绍: #### 一、JNI 基础概念 JNI 是一种标准接口,用于连接 Java 和本地代码(通常是 C 或 C++)。它使得开发者可以在 Java 应用程序中调用本地方法以及访问本地数据结构[^1]。 #### 二、JNI 方法表与函数指针 JNI 使用一组预定义的函数指针集合来完成其功能。这些函数指针被封装在一个名为 `JNIEnv` 的结构体中。每当 JVM 加载一个本地库时,都会传递一个指向该环境变量的指针给本地方法。这个指针包含了所有可用的 JNI 函数地址列表,从而让本地代码能够执行各种操作,比如创建对象、调用方法等[^4]。 #### 三、JNI_OnLoad 机制 当加载动态链接库时,JVM 会寻找并调用其中的一个特殊入口点——`JNI_OnLoad()` 函数。此函数负责初始化一些特定于平台的功能,并返回支持版本号给虚拟机。如果成功,则继续正常流程;否则终止加载过程。 #### 四、类型映射 为了使两种不同类型的系统之间顺利通信,在设计上需要考虑两者间的数据表示差异问题。因此,JNI 定义了一套严格的规则用来描述如何将 Java 数据类型转换成对应的 native 类型及其反向变换方式。 #### 五、异常处理 在跨语言边界的情况下,错误传播变得复杂起来。为此,JNI 提供了一个简单的模型来进行异常管理:一旦发生任何运行期错误(如数组越界),就会设置当前线程上的全局标志位表明存在未捕获到的异常情况;随后所有的后续JNI调用都将失败直到显式清除为止。 #### 六、性能优化建议 由于每次跨越 Java 到 Native 层面都需要付出一定代价,所以应该尽量减少不必要的切换次数以提升效率。例如可以把多次简单请求打包成一次复合操作再提交过去处理等等[^2]。 #### 七、方法签名的重要性 考虑到 Java 支持方法重载特性,仅靠名字本身不足以唯一确定某个具体的方法实体。于是引入了基于参数列表加上返回值得形式化表达字符串即所谓的 “Method Signature”,以便准确无误地定位目标成员函数位置[^3]。 ```c JNIEXPORT void JNICALL Java_MyClass_myNativeMethod(JNIEnv* env, jobject obj){ jclass cls = (*env)->GetObjectClass(env,obj); } ``` 上述代码片段展示了如何获取传入对象所属类别的典型做法之一。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值