兩個用途一直是泛化服務,一種是泛化引用。前者是為了provider省事,后者是消費者省事。先介紹泛化服務怎么做到的:
比如提供者想省事,雖然提供了10個方法,但是不想在接口里面寫十個方法,也就不用給這十個方法做函數聲明、參數聲明了。直接通過:
ServiceConfig<GenericService> service = new ServiceConfig<GenericService>(); service.setApplication(new ApplicationConfig("generic-provider")); service.setRegistry(new RegistryConfig("N/A")); service.setProtocol(new ProtocolConfig("dubbo", 29581)); service.setInterface(DemoService.class.getName()); service.setRef(new GenericService() { public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException { if ("sayName".equals(method)) { return "Generic " + args[0]; } if ("throwDemoException".equals(method)) { throw new GenericException(DemoException.class.getName(), "Generic"); } if ("getUsers".equals(method)) { return args[0]; } return null; } }); service.export();
也就是通過method不同,直接返回不同處理結果,隱藏了方法和參數聲明。上面雖然 service.setInterface(DemoService.class.getName()),這里傳入的是接口的str名稱。也就是說通過generic,provider已經完全不依賴interface了,只是用到這個接口的名稱字符串用做servericekey用的。
之所以能這樣操作,消費者在調用的時候,需要在url里面指定generic=true,那么在經過filter鏈的時候,在GenericImplFilter會做generic處理
把method-name設置成$invoke
parameter-types由於提供者不一定有,於是傳入類型的string類型。
args按照pojo或者java-bean進行序列化成一個map,里面指定了參數的class類型、每個filed的value。
provider不會把這個map做逆序列化處理,直接原樣返回這個map,所以可以看到這個generic的provider能夠處理的東西比較有限。消費者在得到結果的時候,依然是一個map,那么在GenericImplFilter里面,把invoke得到的結果逆序列化成具體的對象。也就是說由GenericImplFilter序列化成一個map,你自己負責逆序列化。
對於泛化引用的話,例子如下:
ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>(); reference.setApplication(new ApplicationConfig("generic-consumer")); reference.setInterface(DemoService.class); reference.setUrl("dubbo://127.0.0.1:29581?scope=remote"); reference.setGeneric(true); GenericService genericService = reference.get(); try { List<Map<String, Object>> users = new ArrayList<Map<String, Object>>(); Map<String, Object> user = new HashMap<String, Object>(); user.put("class", "com.alibaba.dubbo.config.api.User"); user.put("name", "actual.provider"); users.add(user); users = (List<Map<String, Object>>) genericService.$invoke("getUsers", new String[]{List.class.getName()}, new Object[]{users});
消費者直接使用$invoke方法,不用考慮provider到底提供了哪些方法,通過字符串getuser調用,參數類型也不用關心,直接用map描述參數的類型和value。
provider在被調用的時候,還是GenericImplFilter這個filter里面,由provider通過map進行逆序列化,畢竟provider提供的方法里面是按照這個參數類型進行處理的,所以必須從map轉化成真正的類型,處理完成以后,還要逆序列化成map才能返回給consumer,因為consumer只認識map,不認識具體參數類型。