dubbo转http方式调用
业务背景:在当前项目下,所有前端请求均通过外层网关转发到后端这边的dubbo服务,现计划去掉网关层,由前端直接http调用后端dubbo。
解决方案:在前端调用方式不变的前提下,后端服务新建controller层(原后端服务无任何controller),做统一请求兼容转发
package cn.***********.controller;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.utils.ReferenceConfigCache;
import org.apache.dubbo.rpc.service.GenericService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Map;/*** Dubbo调用controller* @Version:1.0* @Desc*/
@Slf4j
@RestController
@RequestMapping("/api/test/")
public class GenericController {@PostMapping("/{service}/{method}")public Object invoke(HttpServletRequest request,@PathVariable("service") String service,@PathVariable("method") String method) {Object result;try {GenericService tarService = this.getTargetService(service);if(tarService == null){throw new RuntimeException("获取service失败");}// 1.解析传入参数String paramStr = this.parseInputStream(request);// 获取目标接口的 Class 对象Class<?> serviceInterface = Class.forName(service);// 获取方法的参数类型String[] parameterTypes = this.getMethodParameterTypes(serviceInterface, method);// 将 JSON 字符串转换为目标参数值Object[] parameters = this.convertParameters(paramStr, parameterTypes);// 调用方法result = tarService.$invoke(method, parameterTypes, parameters);} catch (Exception e) {log.error("服务调用失败, service={},method={}",service, method, e);throw new ErrorCodeException("000000", "系统异常,请稍后重试");}return result;}/*** 获取请求文本** @return*/public String parseInputStream(HttpServletRequest request) {try {ServletInputStream inputStream = request.getInputStream();StringBuilder content = new StringBuilder();int size = request.getContentLength();byte[] b = new byte[size];int lens;while ((lens = inputStream.read(b)) > 0) {content.append(new String(b, 0, lens, "utf-8"));}return content.toString();} catch (IOException e) {log.error("请求报文解析失败", e);throw new RuntimeException("请求报文解析异常");}}/*** 获取目标dubbo服务* @params [service]* @return org.apache.dubbo.rpc.service.GenericService* @desc*/private GenericService getTargetService(String service){// 应用信息ApplicationConfig application = SpringBeanUtils.getBean(ApplicationConfig.class);// 注册中心发现RegistryConfig registry = SpringBeanUtils.getBean(RegistryConfig.class);// 引用远程服务ReferenceConfig<GenericService> reference = new ReferenceConfig<>();reference.setApplication(application);reference.setRegistry(registry);reference.setProtocol("dubbo");reference.setInterface(service);reference.setTimeout(10000);reference.setRetries(0);// 声明为泛化接口reference.setGeneric(true);ReferenceConfigCache cache = ReferenceConfigCache.getCache();GenericService genericService = cache.get(reference);if(genericService == null){genericService = reference.get();}return genericService;}/*** 将 JSON 字符串转换为目标参数值* @params [paramStr, parameterTypes]* @return java.lang.Object[]* @author wu.zeng* @date 2025/2/21 13:44* @desc*/private Object[] convertParameters(String paramStr, String[] parameterTypes) {Object[] parameters = new Object[parameterTypes.length];for (int i = 0; i < parameterTypes.length; i++) {String paramType = parameterTypes[i];switch (paramType) {case "java.lang.String":parameters[i] = paramStr;break;case "java.lang.Integer":parameters[i] = Integer.parseInt(paramStr);break;case "java.lang.Long":parameters[i] = Long.parseLong(paramStr);break;case "java.util.Map":parameters[i] = JSON.parseObject(paramStr, new TypeReference<Map<String, Object>>() {});break;case "java.util.List":parameters[i] = JSON.parseObject(paramStr, new TypeReference<List<Object>>() {});break;default:// 如果是自定义类型,使用反射或 JSON 反序列化try {Class<?> clazz = Class.forName(paramType);parameters[i] = JSON.parseObject(paramStr, clazz);} catch (ClassNotFoundException e) {throw new RuntimeException("不支持的类型: " + paramType, e);}}}return parameters;}/** 获取目标方法的参数类型* @params [serviceInterface, methodName]* @return java.lang.String[]* @desc*/public String[] getMethodParameterTypes(Class<?> serviceInterface, String methodName) {for (Method method : serviceInterface.getMethods()) {// 由于不支持重载,因此这里可以根据 methodName 来匹配方法if (method.getName().equals(methodName)) {Parameter[] parameters = method.getParameters();String[] parameterTypes = new String[parameters.length];for (int i = 0; i < parameters.length; i++) {parameterTypes[i] = parameters[i].getType().getName();}return parameterTypes;}}throw new RuntimeException("方法未找到: " + methodName);}
}
相关文章:
dubbo转http方式调用
业务背景:在当前项目下,所有前端请求均通过外层网关转发到后端这边的dubbo服务,现计划去掉网关层,由前端直接http调用后端dubbo。 解决方案:在前端调用方式不变的前提下,后端服务新建controller层…...
HybridCLR+Adressable+Springboot热更
本文章会手把手教大家如何搭建HybridCLRAdressableSpringboot热更。 创作不易,动动发财的小手点个赞。 安装华佗 首先我们按照官网的快速上手指南搭建一个简易的项目: 快速上手 | HybridCLR 注意在热更的代码里添加程序集。把用到的工具放到程序集里…...
金融行业专题|某基金公司基于超融合信创平台支持人大金仓数据库的性能评测
随着“自主可控”在 IT 基础设施领域不断深化,数据库的国产化替代也被很多金融机构提上日程。为了保证性能,大部分国产数据库都基于信创架构的裸金属服务器部署。在国产虚拟化/超融合平台上,国产数据库性能表现如何?尤其是搭配信创…...
父组件用的是原生监听,子组件用的是onClick,子组件添加了stopPropagation还是没有阻止传播
父组件用事件监听,子组件用onClick,即使子组件加了stopPropagation还是没有阻止冒泡。父组件可能使用原生的addEventListener来绑定事件,而子组件用的是React的onClick事件。这时候,虽然子组件调用了e.stopPropagation()ÿ…...
【问题解决方案】随笔 - vscode里面出现双环境解决方案
1.问题重述 (.venv) (base) 2.解决方案 看是conda还是venv环境,先给退出了 1.conda 比如Anaconda 的 (base) 环境,使用 conda deactivate2.venv deactivate然后重新激活环境即可 END...
什么是 Java 中的线程安全?
回答 Java 中的线程安全(Thread Safety)指的是在多线程环境下,当多个线程同时访问和操作共享资源(如对象、变量、数据结构等)时,能够保证程序的正确性,不会出现数据不一致、竞争条件࿰…...
【2025全网最新最全】前端Vue3框架的搭建及工程目录详解
文章目录 安装软件Node.js搭建Vue工程创建Vue工程精简Vue项目文件 Vue工程目录的解读网页标题的设置设置全局样式路由配置 安装软件Node.js 下载地址:https://nodejs.org/zh-cn/ 安装完成后,打开cmd,查看环境是否准备好 node -v npm -vnpm使用之前一定…...
大白话JavaScript闭包在实际项目中有哪些应用场景?
大白话JavaScript闭包在实际项目中有哪些应用场景? 闭包是指有权访问另一个函数作用域中的变量的函数。在实际项目中,闭包有很多应用场景,以下是一些常见的例子: 数据封装和隐私保护 场景:在开发中,有时…...
R 语言科研绘图第 27 期 --- 密度图-分组
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
QT各种版本下载安装
参考链接: 【Qt】超详细!Qt4.8.6和VS2010的配置及使用 由于QT官网一般现在进不去,所以下载一些QT版本只能通过镜像或者以前下载存储的安装包来进行,现在推荐两种方法 从参考链接中搬过来: 方案一:国内镜…...
信息系统的安全防护
文章目录 引言**1. 物理安全****2. 网络安全****3. 数据安全****4. 身份认证与访问控制****5. 应用安全****6. 日志与监控****7. 人员与管理制度****8. 其他安全措施****9. 安全防护框架**引言 从技术、管理和人员三个方面综合考虑,构建多层次、多维度的安全防护体系。 信息…...
TCPDF 任意文件读取漏洞:隐藏在 PDF 生成背后的危险
在网络安全的世界里,漏洞就像隐藏在黑暗中的“定时炸弹”,稍有不慎就会引发灾难性的后果。今天,我们要聊的是一个与 PDF 生成相关的漏洞——TCPDF 任意文件读取漏洞。这个漏洞可能让攻击者轻松读取服务器上的敏感文件,甚至获取整个…...
如何解决svn st中出现!(冲突)的问题
在 SVN(Subversion)中,svn status 命令用于查看工作副本的状态。当你看到 ! 符号时,通常表示文件或目录在工作副本中丢失(missing)。以下是解决这个问题的步骤: 1. 理解 ! 的含义 ! 表示该文件…...
Redis|复制 REPLICA
文章目录 是什么能干嘛怎么玩案例演示复制原理和工作流程复制的缺点 是什么 官网地址:https://redis.io/docs/management/replication/Redis 复制机制用于将数据从一个主节点(Master)复制到一个或多个从节点(Slave)&a…...
水利 2月26日练习
测量前准备 使用数字万用表的蜂鸣器档,可以高速检验电解电容器的质量好坏。测量方法如图5-14所示。将数字万用表拨至蜂鸣器档,用两支表笔区分与被测电容器Cx的两个引脚接触,应能听到一阵急促的蜂鸣声,随即声响中止,同时…...
Windows逆向工程入门之LOOP与REP指令的深度解析
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 1. LOOP 指令 概念 操作过程 用途 示例代码 扩展知识点:循环优化 2. REP 指令 概念 操作过程 用途 示例代码 扩展知识点:条件前缀 3. LOCK 指令 概念…...
[Web 安全] PHP 反序列化漏洞 —— PHP 序列化 反序列化
关注这个专栏的其他相关笔记:[Web 安全] 反序列化漏洞 - 学习笔记-CSDN博客 0x01:PHP 序列化 — Serialize 序列化就是将对象的状态信息转化为可以存储或传输的形式的过程,在 PHP 中,通常使用 serialize() 函数来完成序列化的操作…...
汽车免拆诊断案例 | 保时捷车发动机偶发熄火故障 2 例
案例1 2008款保时捷卡宴车行驶中发动机偶发熄火 故障现象 一辆2008款保时捷卡宴车,搭载4.8 L 自然吸气发动机,累计行驶里程约为21万km。车主反映,该车行驶中发动机偶发熄火;重新起动,发动机能够起动着机ÿ…...
Python游戏编程之赛车游戏6-2
3.2 move()方法的定义 Player类的move()方法用于玩家控制汽车左右移动,当玩家点击键盘上的左右按键时,汽车会相应地进行左右移动。 move()方法的代码如图7所示。 图7 move()方法的代码 其中,第20行代码通过pygame.key.get_pressed()函数获…...
数据安全_笔记系列09_人工智能(AI)与机器学习(ML)在数据安全中的深度应用
数据安全_笔记系列09_人工智能(AI)与机器学习(ML)在数据安全中的深度应用 人工智能与机器学习技术通过自动化、智能化的数据分析,显著提升了数据分类、威胁检测的精度与效率,尤其在处理非结构化数据、复杂…...
渗透测试【order by盲注实践】
实践环境基于sqli-lab靶场的第46关进行 bool盲注 代码如下: import requests from bs4 import BeautifulSoup# 定义获取用户名的函数,使用 BeautifulSoup 解析 HTML 页面,提取用户名信息 def get_username(resp):soup BeautifulSoup(resp,…...
ROS的action通信——实现阶乘运算(三)
在ROS中除了常见的话题(topic)通信、服务(server)通信等方式,还有action通信这一方式,由于可以实时反馈任务完成情况,该通信方式被广泛运用于机器人导航等任务中。本文将通过三个小节的分享,实现基于action通信的阶乘运…...
007:Cesium.ScreenSpaceEventHandler 知识详解,示例代码
查看本专栏目录 - 本文是第 007个API内容详解 vue+cesium 示例教程200+目录 文章目录 一、ScreenSpaceEventHandler 的基本概念初始化 ScreenSpaceEventHandler二、注册事件**常见事件类型**三、注销事件四、示例代码:鼠标移动时显示坐标信息五、示例代码:鼠标左键点击拾取地…...
期权帮|股指期货基差和价差有什么区别?
锦鲤三三每日分享期权知识,帮助期权新手及时有效地掌握即市趋势与新资讯! 股指期货基差和价差有什么区别? 一、股指期货基差 股指期货基差是指股指期货价格与其对应的现货指数价格之间的差额。 股指期货基差计算公式:基差 现…...
WebSocketHandler 是 Spring Framework 中用于处理 WebSocket 通信的接口
WebSocketHandler 是 Spring Framework 中用于处理 WebSocket 通信的接口,其主要作用是定义了如何处理 WebSocket 的各种事件和消息。以下是 WebSocketHandler 的主要作用和功能: ### 1. 处理 WebSocket 生命周期事件 WebSocketHandler 定义了多个方法来…...
内网渗透测试-Vulnerable Docker靶场
靶场来源: Vulnerable Docker: 1 ~ VulnHub 描述:Down By The Docker 有没有想过在容器中玩 docker 错误配置、权限提升等? 下载此 VM,拿出您的渗透测试帽并开始使用 我们有 2 种模式: - HARD:这需要您将 d…...
一键导出数据库表到Excel
工作中,我们经常需要将数据库表导出到Excel,通常我们会用数据库编辑器之类的工具提供的导出功能来导出,但是它们的导出功能通常都比较简单。 这篇文章将介绍一种简单易用并且功能强大的导出方法。 新增导出 打开的卢导表工具,新…...
2025年电气工程与智能系统国际学术会议(IC2EIS 2025)
重要信息 官网:www.ic2eis.org(点击了解参会投稿等) 时间:2025年3月14-16日 地点:中国河南省郑州市 简介 2025年电气工程与智能系统国际学术会议(IC2EIS 2025)将于2025年3月14-16日在中国郑州举行。会议旨在为电气…...
Activiti 5 + Spring Boot全流程开发指南
目录 一、环境搭建(Spring Boot 2.x) 1.1 依赖配置 1.2 配置文件 二、流程定义与部署 2.1 创建BPMN文件(leave.bpmn) 2.2 流程部署服务 三、流程操作核心实现 3.1 启动流程实例 3.2 查询待办任务 四、审批流程处理 4.1 …...
docker安装etcd:docker离线安装etcd、docker在线安装etcd、etcd镜像下载、etcd配置详解、etcd常用命令、安装常见问题总结
官方网站 官方网址:etcd 二进制包下载:Install | etcd GitHub社区项目:etcd-io GitHub GitHub社区项目版本历史:Releases etcd-io/etcd GitHub 一、镜像下载 1、在线下载 在一台能连外网的linux上执行docker镜像拉取命令…...
