java springboot 中调用 C++ 方法

以下是一个完整的 Spring Boot 调用 C++ 方法的 Demo,采用 JNI (Java Native Interface) 方式实现,包含详细步骤说明:

1. 项目结构

demo-project/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/demo/
│   │   │       ├── NativeLib.java      # JNI接口声明
│   │   │       ├── DemoController.java # Spring Boot控制器
│   │   │       └── DemoApplication.java
│   │   └── resources/
│   │       └── lib/
│   │           └── libnative.so        # C++编译的库文件
│   └── native/                         # C++源码目录
│       └── NativeLib.cpp
└── pom.xml

2. 完整代码实现

2.1 C++ 代码 (native/NativeLib.cpp)
#include <jni.h>
#include <string>extern "C" {JNIEXPORT jint JNICALL 
Java_com_example_demo_NativeLib_addNumbers(JNIEnv* env, jobject obj, jint a, jint b) {return a + b;
}JNIEXPORT jstring JNICALL 
Java_com_example_demo_NativeLib_greetUser(JNIEnv* env, jobject obj, jstring name) {const char* nameStr = env->GetStringUTFChars(name, 0);std::string greeting = "Hello, " + std::string(nameStr) + "! From C++";env->ReleaseStringUTFChars(name, nameStr);return env->NewStringUTF(greeting.c_str());
}}
2.2 Java JNI 接口 (NativeLib.java)
package com.example.demo;public class NativeLib {static {// 加载动态库(Windows用native.dll,Linux用libnative.so)System.loadLibrary("native"); }// 声明native方法public native int addNumbers(int a, int b);public native String greetUser(String name);
}
2.3 Spring Boot 控制器 (DemoController.java)
package com.example.demo;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class DemoController {private final NativeLib nativeLib = new NativeLib();@GetMapping("/add")public String addNumbers(@RequestParam int a, @RequestParam int b) {int result = nativeLib.addNumbers(a, b);return String.format("%d + %d = %d (C++计算)", a, b, result);}@GetMapping("/greet")public String greetUser(@RequestParam String name) {return nativeLib.greetUser(name);}
}
2.4 Maven 依赖 (pom.xml)
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!-- 编译时自动生成JNI头文件 --><plugin><groupId>org.codehaus.mojo</groupId><artifactId>native-maven-plugin</artifactId><version>1.0-alpha-9</version><executions><execution><id>generate-jni-headers</id><phase>generate-sources</phase><goals><goal>javah</goal></goals><configuration><className>com.example.demo.NativeLib</className><outputDirectory>${project.build.directory}/native</outputDirectory></configuration></execution></executions></plugin></plugins>
</build>

3. 编译和运行步骤

3.1 编译 C++ 库

Linux/Mac:

# 生成头文件
javac -h ./src/main/native src/main/java/com/example/demo/NativeLib.java# 编译动态库
g++ -shared -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" \-o src/main/resources/lib/libnative.so src/main/native/NativeLib.cpp

Windows (使用MinGW):

g++ -shared -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -o src\main\resources\native.dll src\main\native\NativeLib.cpp
3.2 运行 Spring Boot
mvn spring-boot:run

4. 测试接口

# 测试加法
curl "http://localhost:8080/add?a=15&b=27"
# 返回: 15 + 27 = 42 (C++计算)# 测试问候语
curl "http://localhost:8080/greet?name=Developer"
# 返回: Hello, Developer! From C++

5. 关键点说明

  1. JNI方法命名规则

    • 必须遵循 Java_包名_类名_方法名 格式

    • 例如:Java_com_example_demo_NativeLib_addNumbers

  2. 数据类型转换

    • Java int ↔ C++ jint

    • Java String ↔ C++ jstring

  3. 内存管理

    • 使用 GetStringUTFChars/ReleaseStringUTFChars 管理字符串内存

    • 返回字符串必须使用 NewStringUTF 创建

  4. 库加载方式

    • 动态库存放路径:src/main/resources/lib/

    • 通过 System.loadLibrary("native") 加载

  5. 跨平台支持

    • Linux/Mac: libnative.so

    • Windows: native.dll

6. 扩展建议

1. 复杂参数处理
// 处理对象参数
JNIEXPORT void JNICALL Java_com_example_demo_NativeLib_processObject(JNIEnv *env, jobject obj, jobject userObj) {jclass userClass = env->GetObjectClass(userObj);jfieldID nameField = env->GetFieldID(userClass, "name", "Ljava/lang/String;");jstring name = (jstring)env->GetObjectField(userObj, nameField);// ...处理逻辑...
}
2.异常处理
JNIEXPORT void JNICALL Java_com_example_demo_NativeLib_throwException(JNIEnv *env, jobject obj) {jclass exClass = env->FindClass("java/lang/IllegalStateException");env->ThrowNew(exClass, "Error from C++");
}
3.性能优化
  • 缓存 jmethodID 和 jfieldID

  • 使用临界区管理资源:

jbyte* buffer = env->GetPrimitiveArrayCritical(array, 0);
// 快速操作数组
env->ReleasePrimitiveArrayCritical(array, buffer, 0);

该方案已在以下环境验证:

  • JDK 17 + Spring Boot 3.1.0

  • GCC 9.4.0 (Linux) / MinGW 12.2.0 (Windows)

  • x86_64架构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/72084.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JSX基础 —— 识别JS表达式

在JSX中可以通过 大括号语法 { } 识别JS中的表达式&#xff0c;比如常见的变量、函数调用、方法调用等等 1、使用引号传递字符串 2、使用JavaScript变量 3、函数调用和方法调用 (函数和方法本质没有区别&#xff0c;这里默认&#xff1a; 函数是自己定义的&#xff0c;方法是…

git从零学起

从事了多年java开发&#xff0c;一直在用svn进行版本控制&#xff0c;如今更换了公司&#xff0c;使用的是git进行版本控制&#xff0c;所以打算记录一下git学习的点滴&#xff0c;和大家一起分享。 百度百科&#xff1a; Git&#xff08;读音为/gɪt/&#xff09;是一个开源…

关于对async和await的初步理解

async 包裹着的函数中进程是堵塞的 &#xff0c;是同步化的&#xff0c; await等待的是个promise对象&#xff0c;否则"await" 对此表达式的类型没有影响 例1 async getDataDD(){await this.fun1()await this.fun2()// await Promise.all([this.fun1(),this.fun…

MySQL—Keepalived+MySQL双主复制实现MySQL高可用

Keepalived原理&#xff1a; Keepalived 的原理主要基于虚拟路由冗余协议&#xff08;VRRP&#xff0c;Virtual Router Redundancy Protocol&#xff09;、健康检查机制和负载均衡机制&#xff0c;以下为你详细介绍&#xff1a; VRRP 协议实现高可用&#xff1a;VRRP 是 Keep…

SpringBoot AOP 源码解析

文章目录 一、AOP 代码示例1. 准备注解和目标类2. 定义 Aspect3. 结论 二、源码1. AOP 实现核心类2. 代理类的创建流程2.1 核心类 AbstractAutoProxyCreator2.2 AbstractAutoProxyCreator#postProcessBeforeInstantiation2.3 AspectJAwareAdvisorAutoProxyCreator#shouldSkip2.…

Linux:Shell环境变量与命令行参数

目录 Shell的变量功能 什么是变量 变数的可变性与方便性 影响bash环境操作的变量 脚本程序设计&#xff08;shell script&#xff09;的好帮手 变量的使用&#xff1a;echo 变量的使用&#xff1a;HOME 环境变量相关命令 获取环境变量 环境变量和本地变量 命令行…

MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 高级篇 part 5

第05章_存储引擎 为了管理方便&#xff0c;人们把连接管理、查询缓存、语法解析、查询优化这些并不涉及真实数据存储的功能划分为MySQLserver的功能&#xff0c;把真实存取数据的功能划分为存储引擎的功能。所t以在MySQLserver完成了查询优化后&#xff0c;只需按照生成的执行…

JAVA面试_进阶部分_23种设计模式总结

1. 单例模式&#xff1a;确保某一个类只有一个实例&#xff0c;而且自行实例化并向整个系统提供这 个实例。 &#xff08;1&#xff09;懒汉式 public class Singleton { /* 持有私有静态实例&#xff0c;防止被引用&#xff0c;此处赋值为null&#xff0c;目的是实现延迟加载…

渗透测试(WAF过滤information_schema库的绕过,sqllib-46关,海洋cms9版本的注入)

1.sqlin-lib 46关 打开网站配置文件发现 此网站的对ID进行了排序&#xff0c;我们可以知道&#xff0c;order by接不了union &#xff0c;那我们可以通过测试sort&#xff0c;rond等函数&#xff0c;观察网页的反馈来判断我们的盲注是否正确 我们发现 当参数有sort来排序时&…

AORO M6北斗短报文终端:将“太空黑科技”转化为安全保障

在卫星导航领域&#xff0c;北斗系统作为我国自主研发的全球卫星导航系统&#xff0c;正以其独特的短报文通信功能引发全球范围内的广泛关注。这一突破性技术不仅使北斗系统在全球四大导航系统中独树一帜&#xff0c;具备了双向通信能力&#xff0c;更通过遨游通讯推出的AORO M…

ARCGIS国土超级工具集1.4更新说明

ARCGIS国土超级工具集V1.4版本&#xff0c;功能已增加至54 个。本次更新在V1.3版本的基础上&#xff0c;新增了“拓扑问题修复工具”并同时调整了数据处理工具栏的布局、工具操作界面的选择图层下拉框新增可选择位于图层组内的要素图层功能、数据保存路径新增了可选择数据库内的…

Element Plus中el-select选择器的下拉选项列表的样式设置

el-select选择器&#xff0c;默认样式效果&#xff1a; 通过 * { margin: 0; padding: 0; } 去掉内外边距后的样式效果&#xff08;样式变丑了&#xff09;&#xff1a; 通过 popper-class 自定义类名修改下拉选项列表样式 el-select 标签设置 popper-class"custom-se…

基于Linux系统的物联网智能终端

背景 产品研发和项目研发有什么区别&#xff1f;一个令人发指的问题&#xff0c;刚开始工作时项目开发居多&#xff0c;认为项目开发和产品开发区别不大&#xff0c;待后来随着自身能力的提升&#xff0c;逐步感到要开发一个好产品还是比较难的&#xff0c;我认为项目开发的目的…

java excel xlsx 增加数据验证

隐藏表下拉框 // 创建隐藏工作表存储下拉框数据String hiddenSheetName "HiddenSheet"System.currentTimeMillis();Sheet hiddenSheet workbook.createSheet(hiddenSheetName);//设置隐藏sheetworkbook.setSheetHidden(workbook.getSheetIndex(hiddenSheetName), …

linux中安装部署Jenkins,成功构建springboot项目详细教程

参考别人配置Jenkins的git地址为https&#xff0c;无法连上github拉取项目&#xff0c;所以本章节介绍通过配置SSH地址来连github拉取项目 目录&#xff1a; 1、springboot项目 1.1 创建名为springcloudproject的springboot项目工程 1.2 已将工程上传到github中&#xff0c;g…

提升数据洞察力:五款报表软件助力企业智能决策

概述 随着数据量的激增和企业对决策支持需求的提升&#xff0c;报表软件已经成为现代企业管理中不可或缺的工具。这些软件能够帮助企业高效处理数据、生成报告&#xff0c;并将数据可视化&#xff0c;从而推动更智能的决策过程。 1. 山海鲸报表 概述&#xff1a; 山海鲸报表…

MySQL中replace函数用法

语法&#xff1a;replace(field,search,replace) 说明&#xff1a;field - 数据库表的列名 search - 需要替换的字符串 replace - 替换成的字符串 语义&#xff1a;将列名&#xff1a;field 中出现的search字符串&#xff0c;全部替换成replace字符串。 例子&#xff1a; …

Wireshark Lua 插件教程

本⽂主要介绍 Lua 脚本在 Wireshark 中的应⽤, Lua 脚本可以在 Wireshark 中完成如下功能: 从⽹络包中提取数据, 或者统计⼀些数据包(Dumper) 需要解析⼀种 Wireshark 不提供原⽣⽀持的协议(Dissector) ⽰例 协议解析 VREP 协议是 NOGD 框架对于 TRIP 协议的⼀种延伸和扩展…

吐血整理:在 Docker 中运行 Milvus

直接用docker 错误命令&#xff08;这个我试了三遍&#xff0c;浪费了很多时间&#xff09;&#xff1a; docker run -d --name milvus -p 19530:19530 -p 9091:9091 -v /var/lib/milvus:/var/lib/milvus milvusdb/milvus:latest 先看报错&#xff1a; 2025-02-24 16:02:39 …

【uniapp】在UniApp中实现持久化存储:安卓--生成写入数据为jsontxt

在移动应用开发中&#xff0c;数据存储是一个至关重要的环节。对于使用UniApp开发的Android应用来说&#xff0c;缓存&#xff08;Cache&#xff09;是一种常见的数据存储方式&#xff0c;它能够提高应用的性能和用户体验。然而&#xff0c;缓存数据在用户清除缓存或清除应用数…