Dubbo的GenericService简介和基本使用

 

简介

GenericService是Dubbo提供的泛化接口,用来进行泛化调用。

GenericService接口只有一个方法:

Object $invoke(String var1, String[] var2, Object[] var3) throws GenericException;

第一个参数是方法名。

第二个参数是一个字符串数组,这是接口方法每个参数类型的全路径。

第三个参数是Object数组,是传给方法的具体参数列表。

Dubbo服务的提供者和消费者都可以使用这个接口,场景略有不同,二者也未必同时存在,可以由提供者使用GenericService,消费者用具体接口类,或者消费者使用GenericService,提供者用具体接口类,或者提供者和消费者都用GenericService,只要指定的接口能对得上,调用都没问题。

下面分别看一下。

 

服务提供者使用GenericService

当服务提供者使用这个接口时,可以省略Interface的代码,省略方法和参数的声明,通过指定接口名称的方式向zookeeper发布Dubbo服务。

这时GenericService就像是一个网关。

举个例子:

@Override
public void afterSingletonsInstantiated() {
    ServiceConfig service = new ServiceConfig();
    ApplicationConfig application = new ApplicationConfig("test-provider");
    service.setApplication(application);
    RegistryConfig registryConfig = new RegistryConfig();
    registryConfig.setAddress("zookeeper://127.0.0.1:2181");
    service.setRegistry(registryConfig);
    service.setInterface("com.suibian.WhateverService");

    GenericService genericService = (method, parameterTypes, args) -> {
        if ("method1".equals(method)) {
            return "method1 result:" + args[0];
        }
        if ("method2".equals(method)) {
            return 12345;
        }
        if (parameterTypes.length == 2
                && parameterTypes[0].equals("java.lang.String")
                && parameterTypes[1].equals("java.lang.Integer")
                && "method3".equals(method)) {
            return "method3,param1:" + args[0] + ",param2:" + args[1];
        }
        return null;
    };
    service.setRef(genericService);
    service.export();
}

大概说明一下:

1,registryConfig里需要写好注册中心地址。zookeeper注册中心格式是这样的:zookeeper://127.0.0.1:2181

2,ServiceConfig.setInterface()用于指定要发布的接口名称,这个名称可以不对应任何的java接口类,甚至可以随便写。在上面的例子中com.suibian.WhateverService这个名字就是随便写的,实际上代码中并没有这个接口类。

3,因为这样发布的Dubbo服务没有具体的接口类,所以invoke()方法的第一个参数String var1(原本是方法名)和第二个参数String[] var2(原本是方法参数类型列表)就脱离了具体接口类的束缚,可以接收任意值,就像上面例子中所写的一样,按照不同的参数执行不同的逻辑,就像一个网关一样。

4,Dubbo服务的发布本身不需要Spring服务启动,但如果把上面的代码放在main()方法中,随着进程结束,发布的Dubbo服务也会立即被取消。

5,向zookeeper中注册好的GenericService在zookeeper中是这样的:

[zk: localhost:2181(CONNECTED) 4] ls /dubbo/com.suibian.WhateverService/providers

[dubbo%3A%2F%2F172.16.111.111%3A20880%2Fcom.suibian.WhateverService%3Fanyhost%3Dtrue%26application%3Dtest-provider%26dubbo%3D2.5.3%26generic%3Dtrue%26interface%3Dcom.suibian.WhateverService%26methods%3D*%26pid%3D3856%26side%3Dprovider%26timestamp%3D1592905521950]

可以看到里面没有方法列表,有generic标识。

 

服务消费者使用GenericService

当服务消费者使用这个接口时,有个好处是不依赖服务提供者的Interface接口类,而是通过指定具体接口类路径的方式,创建消费者,并去zookeeper查找对应的提供者,然后发起调用。

举个例子:

public static void test3() {

    ApplicationConfig application = new ApplicationConfig("test-consumer"); //参数为dubbo消费方的名称
    RegistryConfig registryConfig = new RegistryConfig();
    registryConfig.setAddress("zookeeper://127.0.0.1:2181");
    application.setRegistry(registryConfig);

    ReferenceConfig reference = new ReferenceConfig();
    reference.setApplication(application);
    reference.setInterface("com.suibian.WhateverService");
    reference.setTimeout(3000);
    reference.setGeneric(true);
    GenericService genericService = reference.get();
    Object object1 = genericService.$invoke("method1", new String[]{"java.lang.String"}, new Object[]{"this is parameter"});    //调用泛化接口
    System.out.println(object1);

    Object object2 = genericService.$invoke("method2", new String[]{"java.lang.String"}, new Object[]{"this is parameter"});    //调用泛化接口
    System.out.println(object2);

    Object object3 = genericService.$invoke("method3", new String[]{"java.lang.String", "java.lang.Integer"}, new Object[]{"ABCD", 1234});    //调用泛化接口
    System.out.println(object3);

}

public static void main(String[] args) {
    test3();
}

根据上面提供者发布的接口,这次调用输出的结果是:

method1 result:this is parameter
12345
method3,param1:ABCD,param2:1234

可以看到,消费者使用GenericService时并不需要启动Spring服务,reference.get()方法会直接向zookeeper注册consumer,然后调用invoke()方法发起调用。

使用时记得加上reference.setGeneric(true);

 

invoke()方法的返回值类型

因为不依赖提供者的接口类,只是指定了接口类名和参数,所以调用时无法知道方法具体的返回值类型。

虽然invoke()方法的返回类型统一都是Object,不过还是能分成以下几种情况:

1,方法的返回类型是简单类型,比如Integer和String,比如这样的方法:

Integer findOne (String code);

返回的类型就是这种简单类型本身。

2,方法的返回类型是单个非简单元素,比如这样的方法:

Student findOne (String code);

返回值类型实际上是HashMap。key是提供者的接口类中方法返回类型的属性名,value是属性值。

3,方法的返回类型是列表,比如这样的方法:

List findList (String code);

返回值类型实际上是ArrayList

 

本文结束

你可能感兴趣的:(框架,Java)