簡介
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>。
本文結束