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<GenericService> service = new ServiceConfig<GenericService>();
    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<GenericService> reference = new ReferenceConfig<GenericService>();
    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<Student> findList (String code);

返回值類型實際上是ArrayList<HashMap>。

 

本文結束

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章