在Java 21中使用JNI技术和CMake来实现Java和C语言的混合开发。

将SQLite和哈希等低级操作与Java代码集成在一起。

有关代码: https://git.wqyblog.cn/wuqiyang312/wqyTools

项目目标是创建一个共享库(wqyToolsJni),并提供Java接口来调用C++的SQLite和哈希功能。

以下是详细的配置步骤,包括Java和C/C++代码的开发、JNI头文件生成,以及使用CMake来构建共享库。

项目结构

首先,创建以下项目结构:

project-root/
├── CMakeLists.txt               # CMake构建文件
├── src/
│   ├── main/
│   │   └── java/cn/wqyblog/wqytools/jni/Jni.java  # Java代码
├── native/
│   ├── library.cpp              # 自定义C++库代码
│   ├── sqlite3Library.cpp       # SQLite相关的C++封装
│   ├── hashLibrary.cpp          # 哈希相关的C++封装
│   ├── sqlite/
│   │   └── sqlite3.c            # SQLite源码
└── build/                       # CMake构建目录

1: 编写Java代码

src/main/java/cn/wqyblog/wqytools/jni/Jni.java中,编写如下Java类,用于定义native方法:

package cn.wqyblog.wqytools.jni;

public class Jni {
    static {
        System.loadLibrary("wqyToolsJni");
    }

    // ==== sqlite ====
    public static native boolean sqliteOpen(String path);
    public static native boolean sqliteClose();
    public static native boolean sqliteCreateTable();
    public static native String sqliteGetConfig(String key);
    public static native boolean sqliteSetConfig(String key, String value);
    public static native boolean sqliteAddConfig(String key, String value);
    public static native boolean sqliteDeleteConfig(String key);

    // ==== hash ====
    public static native String calcFileHash(String filename, String algorithm);
    public static native String calcStringHash(String str, String algorithm);
}

2: 编译Java文件并生成JNI头文件

在项目根目录下运行以下命令来编译Java代码并生成头文件:

javac -h native/ src/main/java/cn/wqyblog/wqytools/jni/Jni.java

这将生成一个cn_wqyblog_wqytools_jni_Jni.h文件,包含了Jni类中定义的所有native方法的声明。

3: 编写C/C++代码

根据生成的cn_wqyblog_wqytools_jni_Jni.h,在native/目录下编写C++代码,以下为示例。

library.cpp

实现sqliteOpensqliteClose等SQLite相关方法:

#include "cn_wqyblog_wqytools_jni_Jni.h"
#include <sqlite3.h>

// SQLite相关的C++代码实现
JNIEXPORT jboolean JNICALL Java_cn_wqyblog_wqytools_jni_Jni_sqliteOpen(JNIEnv* env, jobject obj, jstring path) {
    // SQLite打开数据库代码
}

JNIEXPORT jboolean JNICALL Java_cn_wqyblog_wqytools_jni_Jni_sqliteClose(JNIEnv* env, jobject obj) {
    // SQLite关闭数据库代码
}

// 其他JNI实现代码...

hashLibrary.cpp

实现calcFileHashcalcStringHash等哈希计算方法:

#include "cn_wqyblog_wqytools_jni_Jni.h"
#include <openssl/sha.h>
#include <string>

// 使用OpenSSL进行文件哈希计算
JNIEXPORT jstring JNICALL Java_cn_wqyblog_wqytools_jni_Jni_calcFileHash(JNIEnv* env, jobject obj, jstring filename, jstring algorithm) {
    // 文件哈希计算代码
}

4: 编写CMakeLists.txt

在项目根目录下编写CMakeLists.txt

cmake_minimum_required(VERSION 3.28)
project(wqyToolsJni)

set(CMAKE_CXX_STANDARD 17)

# 找到 OpenSSL
find_package(OpenSSL REQUIRED)

add_library(wqyToolsJni SHARED
    native/sqlite/sqlite3.c
    native/library.cpp
    native/sqlite3Library.cpp
    native/hashLibrary.cpp)

# 包含 OpenSSL 头文件和Java头文件
find_package(Java REQUIRED)
include_directories(${Java_INCLUDE_DIRS})
include_directories(native)
target_include_directories(wqyToolsJni PRIVATE ${OPENSSL_INCLUDE_DIR})

# 链接 OpenSSL 库
target_link_libraries(wqyToolsJni PRIVATE OpenSSL::SSL OpenSSL::Crypto)

Step 5: 使用CMake构建共享库

进入build/目录,生成并编译共享库:

mkdir build && cd build
cmake ..
make

生成的libwqyToolsJni.so共享库将放在build/目录中。

Step 6: 运行Java测试

在Java代码中设置动态库的加载路径,然后运行Jni类中的测试代码:

public static void main(String[] args) {
    System.load("/path/to/libwqyToolsJni.so"); // 手动加载路径
    boolean success = Jni.sqliteOpen("test.db");
    System.out.println("SQLite open success: " + success);
}

使用以下命令运行测试代码:

java -cp src/main/java cn.wqyblog.wqytools.jni.Jni

标签: java, c/c++