1. 前言
之前在公司开发的时候, 需要用到内部的组件, 尽管提供了jar包, 但是jar包底层是通过Java本地方法实现的, 所以仅仅导入jar包并不能正常使用, 还需要安装内部组件的环境. 所以写这篇文章记录Java本地方法的使用, 帮助自己熟悉这块的使用.
2. 基础使用
基于Linux环境, 这个章节简单介绍如何实现一个Java本地方法.
第一步: 建立一个普通的java类, 添加一个方法, 在方法返回值前加 native
public class ClassMethod {
//本地方法可以是静态的也可以是非静态的;
public static native void greeting();
}
第二步: 编译这个java类, 得到ClassMethod.class文件
javac ClassMethod.java
第三步: 找到当前类编译的.class文件, 使用命令行生成.h文件
javah ClassMethod
第四步: 查看ClassMethod.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ClassMethod */
#ifndef _Included_ClassMethod
#define _Included_ClassMethod
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: ClassMethod
* Method: greeting
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_ClassMethod_greeting
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
第五步: 新建cpp文件, 并写逻辑代码(我这边命名为main.cpp,其实是可以随意命名的)
#include "ClassMethod.h"
#include <stdio.h>
JNIEXPORT void JNICALL Java_ClassMethod_greeting(JNIEnv *, jclass){
printf("hello world!");
}
第六步: 将main.cpp文件和ClassMethod.h放到一个目录下, 并执行指令生成动态链接库.so文件
gcc -fPIC -I /home/ganlu/java/jdk1.8.0_144/include/ -I /home/ganlu/java/jdk1.8.0_144/include/linux/ -shared -o libHello.so main.cpp
第七步: 将动态链接库复制到java项目中
public class ClassMethod {
static
{
System.load("/home/ganlu/java/workplace/libHello.so");
}
//本地方法可以是静态的也可以是非静态的;
public static native void greeting();
public static void main(String args[]){
greeting();
}
}
第八步: 重新编译ClassMethod.java并执行
javac ClassMethod.java
java ClassMethod
运行结果:
hello world!
3. 几个问题
3.1 动态链接库
我这边动态链接库的加载是通过绝对路径的指定来实现的, 而实际中, 这种绝对路径的指定肯定是不好的.
System.load("/home/ganlu/java/workplace/libHello.so");
网上流传比较多的一种做法是如下(这里要注意, .so文件的命名一定要规范, 以lib开头, 以.so结尾):
System.loadLibrary("Hello");
但是用这种方法直接运行, 会报错.
Exception in thread "main" java.lang.UnsatisfiedLinkError: no Hello in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at ClassMethod.<clinit>(ClassMethod.java:4)
3.1.1 解决方法一:通过Java运行参数指定java.library.path
java -Djava.library.path=. ClassMethod
3.1.2 解决方法二:通过配置 LD_LIBRARY_PATH 环境变量
sudo gedit /etc/profile
export LD_LIBRARY_PATH=/home/ganlu/java/workplace
3.2 工作流程图
3.3 常见异常
如果出现以下异常, 则说明.so文件不对, 是因为java 程序在调用.so时候, 不能找到native method 方法的实现.
主要是因为在.so中, 可能xxx.h头文件中的接口名和xxx.cpp源文件中的实现函数名不一致导致的.
Exception in thread "main" java.lang.UnsatisfiedLinkError: test.ClassMethod.greeting()V
at test.ClassMethod.greeting(Native Method)
at test.ClassMethod.main(ClassMethod.java:11)
4. 参考链接
https://blog.youkuaiyun.com/qq_31105311/article/details/51255479
https://www.cnblogs.com/zh1164/p/6283831.html
https://blog.youkuaiyun.com/missingu1314/article/details/12650725