dubbo泛化调用

泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况,参数及返回值中的所有 POJO 均用 Map 表示,通常用于框架集成,比如:实现一个通用的服务测试框架,可通过 GenericService 调用所有服务实现。

dubbo支持泛化调用 
1、开发工程中 有时候想要测试dubbo接口 需要自定义用例,比较麻烦 
2、无法调用服务器上的dubbo测试 
3、无法随意调用多版本的服务 

由于dubbo支持泛化调用 所以这些问题就迎刃而解了

复制代码
/*
 * Copyright 1999-2011 Alibaba Group.
 *  
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0
 *  
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.dubbo.rpc.service;
 
/**
 * 通用服务接口*/
public interface GenericService {
 
    /**
     * 泛化调用
     * 
     * @param method 方法名,如:findPerson,如果有重载方法,需带上参数列表,如:findPerson(java.lang.String)
     * @param parameterTypes 参数类型
     * @param args 参数列表
     * @return 返回值
     * @throws Throwable 方法抛出的异常
     */
    Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException;
 
}
复制代码
复制代码
    // 当前应用的信息
    private static ApplicationConfig application = new ApplicationConfig();

    // 注册中心信息缓存
    private static Map<String, RegistryConfig> registryConfigCache = new ConcurrentHashMap<>();

    // 各个业务方的ReferenceConfig缓存
    private static Map<String, ReferenceConfig> referenceCache = new ConcurrentHashMap<>();

    static {
        application.setName("consumer-test");
    }


    /**
     * dubbp接口泛化调用
     * @param interfaceName 类名包含全路径:com.xx.xxService
     * @param methodName 方法名 qryAvailableBonusForPay
     * @param address zk地址 dubbo.registry.address=zookeeper://xx:xx?backup=xx:xx,xx:xx
     * @param group zk分组 dubbo.registry.group=GLOBAL_REGISTRY
     * @param paramTypes 参数类型 new String[]{"java.lang.String","com.xx.MyParam"}
     * @param params 参数值 new Object[]{"123", new HashMap<>()}
     * @return object
     */
    public static Object invoke(String interfaceName, String methodName, String address, String group, String[] paramTypes, Object[] params) throws BaseAppException {
        ReferenceConfig reference = getReferenceConfig(interfaceName, address, group);// 用org.apache.dubbo.rpc.service.GenericService可以替代所有接口引用
//        GenericService genericService = (GenericService) reference.get();
        // ReferenceConfig的get方法创建代理对象是一个很重的操作,在泛化调用时如果每次都用新的ReferenceConfig对象的get方法创建代理对象,
        // 将浪费大量的cpu时间并可能导致内存泄露(内存泄露问题9.0.8已修复)
        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
        GenericService genericService = (GenericService) cache.get(reference);
// 基本类型以及Date,List,Map等不需要转换,直接调用
        Object object = genericService.$invoke(methodName, paramTypes, params);return object;
    }


    private static ReferenceConfig getReferenceConfig(String interfaceName, String address, String group) throws BaseAppException {// 引用远程服务 封装了所有与注册中心及服务提供方连接
        ReferenceConfig referenceConfig = referenceCache.get(interfaceName);
        if (null == referenceConfig) {
            referenceConfig = new ReferenceConfig<>();
            // dubbo consumer的application配置
            referenceConfig.setApplication(application);
            // 注册中心信息
            referenceConfig.setRegistry(getRegistryConfig(address, group));
            // 弱类型接口名
            referenceConfig.setInterface(interfaceName);
            // 声明为泛化接口
            referenceConfig.setGeneric(true);
            referenceCache.put(interfaceName, referenceConfig);
        }
return referenceConfig;
    }


    private static RegistryConfig getRegistryConfig(String address, String group) throws BaseAppException {
        String key = address + "-" + group;
        RegistryConfig registryConfig = registryConfigCache.get(key);
        if (null == registryConfig) {
            registryConfig = new RegistryConfig();
            registryConfig.setAddress(address);
            registryConfig.setGroup(group);
            registryConfigCache.put(key, registryConfig);
        }
return registryConfig;
    }
复制代码

以上代码为本地测试工具类

 

 

 

在 Java 代码获取 barService 并开始泛化调用:

GenericService barService = (GenericService) applicationContext.getBean("barService");
Object result = barService.$invoke("sayHello", new String[] { "java.lang.String" }, new Object[] { "World" });

通过API方式

复制代码
import com.alibaba.dubbo.rpc.service.GenericService; 
... 

// 引用远程服务 
// 该实例很重量,里面封装了所有与注册中心及服务提供方连接,请缓存
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); 
// 弱类型接口名
reference.setInterface("com.xxx.XxxService");  
reference.setVersion("1.0.0");
// 声明为泛化接口 
reference.setGeneric(true);  

// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用  
GenericService genericService = reference.get(); 

// 基本类型以及Date,List,Map等不需要转换,直接调用 
Object result = genericService.$invoke("sayHello", new String[] {"java.lang.String"}, new Object[] {"world"}); 

// 用Map表示POJO参数,如果返回值为POJO也将自动转成Map 
Map<String, Object> person = new HashMap<String, Object>(); 
person.put("name", "xxx"); 
person.put("password", "yyy"); 
// 如果返回POJO将自动转成Map 
Object result = genericService.$invoke("findPerson", new String[]
{"com.xxx.Person"}, new Object[]{person});
...
复制代码

如果参数中对象存在复杂结构(也就是参数类型中某个参数是复杂对象),这时,可以使用map来包入参,入参类型可以通过class属性保留下来,如果POJO 数据:

Person person = new PersonImpl(); 
person.setName("xxx"); 
person.setPassword("yyy");

可用下面 Map 表示:

Map<String, Object> map = new HashMap<String, Object>(); 
// 注意:如果参数类型是接口,或者List等丢失泛型,可通过class属性指定类型。
map.put("class", "com.xxx.PersonImpl"); 
map.put("name", "xxx"); 
map.put("password", "yyy");
 
demo举例
复制代码
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.rpc.service.GenericService;
import com.alibaba.fastjson.JSON;

import java.util.HashMap;
import java.util.Map;

public class TestDubboGeneric {
    public static void main(String[] args) {
        ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
        // 当前dubbo consumer的application配置,不设置会直接抛异常
        ApplicationConfig applicationConfig = new ApplicationConfig();
        applicationConfig.setName("xxx_test_service");
        // 注册中心配置
        RegistryConfig registryConfig = new RegistryConfig();
        // 注册中心这里需要配置上注册中心协议,例如下面的zookeeper
        registryConfig.setAddress("zookeeper://192.168.0.1:2181");
        registryConfig.setGroup("test_group");
        reference.setApplication(applicationConfig);
        reference.setRegistry(registryConfig);
        // 设置调用的reference属性,下面只设置了协议、接口名、版本、超时时间
        reference.setProtocol("dubbo");
        reference.setInterface("com.xxx.test.TestService");
        reference.setVersion("1.0.0");
        reference.setTimeout(1000);
        // 声明为泛化接口
        reference.setGeneric(true);
        // GenericService可以接住所有的实现
        GenericService genericService = reference.get();
        // 构造复杂参数,下面的示例中,头两个参数为string类型,后一个是一个复杂类型,但都可以通过map构造。
        Map<String, Object> param = new HashMap<>();
        param.put("test1", "a");
        param.put("test2", "b");
        Map<String,Object> thirdParam = new HashMap<>();
        thirdParam.put("class","java.util.Map");
        thirdParam.put("subParam1","c");
        thirdParam.put("subParam2","d");
        param.put("test3",thirdParam);
        Object result = genericService.$invoke("myMethod", new String[]{"java.lang.String", "java.lang.String", "com.xxxtest.MyParam"}, new Object[]{"123", "ddd",param});
        System.out.println(JSON.toJSONString(result));
    }
}
复制代码

 

优化:
 
//        GenericService genericService = (GenericService) reference.get();
        // ReferenceConfig的get方法创建代理对象是一个很重的操作,在泛化调用时如果每次都用新的ReferenceConfig对象的get方法创建代理对象,
        // 将浪费大量的cpu时间并可能导致内存泄露
        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
        GenericService genericService = (GenericService) cache.get(reference);

 

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

posted on   胡子就不刮  阅读(3394)  评论(0编辑  收藏  举报

编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示