dubbo转http方式调用方式

 更新时间:2025年10月22日 08:35:42   作者:安之若素^  
当前项目计划去掉网关层,前端将直接通过HTTP调用后端dubbo服务,为此,后端需新增controller层,实现请求兼容和统一转发,保证前端调用方式不变

业务背景

在当前项目下,所有前端请求均通过外层网关转发到后端这边的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);
    }
}

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java使用定时器编写一个简单的抢红包小游戏

    Java使用定时器编写一个简单的抢红包小游戏

    这篇文章主要为大家介绍了Java如何使用定时器编写一个简单的抢红包小游戏,文中的示例代码讲解详细,感兴趣的小伙伴可以尝试一下
    2022-07-07
  • MyBatis分页插件PageHelper的使用与原理

    MyBatis分页插件PageHelper的使用与原理

    提到插件相信大家都知道,插件的存在主要是用来改变或者增强原有的功能,MyBatis中也一样,下面这篇文章主要给大家介绍了关于Mybatis第三方PageHelper分页插件的使用与原理,需要的朋友可以参考下
    2023-02-02
  • java实现线性表及其算法

    java实现线性表及其算法

    线性表是最简单和最常用的一种数据结构,它是有n个体数据元素(节点)组成的有限序列,这篇文章主要介绍了java实现线性表及其算法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • 用Java编程输出万年历的功能实现

    用Java编程输出万年历的功能实现

    这篇文章主要介绍了用Java编程输出万年历的功能实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • Java基于栈方式解决汉诺塔问题实例【递归与非递归算法】

    Java基于栈方式解决汉诺塔问题实例【递归与非递归算法】

    这篇文章主要介绍了Java基于栈方式解决汉诺塔问题的方法,结合实例形式分析了java栈方式采用递归与非递归算法解决汉诺塔问题的相关操作技巧,需要的朋友可以参考下
    2017-11-11
  • 使用ObjectMapper解析json不用一直new了

    使用ObjectMapper解析json不用一直new了

    这篇文章主要为大家介绍了使用ObjectMapper解析json不用一直new了的方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • mybatis如何在一个update标签中写多条update语句

    mybatis如何在一个update标签中写多条update语句

    这篇文章主要介绍了mybatis如何在一个update标签中写多条update语句问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • tomcat9使用指定的JDK版本完整步骤记录

    tomcat9使用指定的JDK版本完整步骤记录

    在服务器部署多个JDK版本的场景下,Tomcat默认读取系统环境变量可能导致版本冲突,下面这篇文章主要介绍了tomcat9使用指定的JDK版本的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-04-04
  • Java版C语言版简单使用静态语言实现动态数组的方法

    Java版C语言版简单使用静态语言实现动态数组的方法

    本文给大家分享java版和C语言版简单使用静态语言实现动态数组的方法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-10-10
  • 详解Java集合中的基本数据结构

    详解Java集合中的基本数据结构

    总有小伙伴让我总结一下Java集合中的基本数据结构的相关知识,今天特地整理了本篇文章,文中有非常详细的介绍,需要的朋友可以参考下
    2021-06-06

最新评论