基于dubbo中Listener的實現(xiàn)方法
這里繼續(xù)dubbo的源碼旅程,在過程中學(xué)習(xí)它的設(shè)計和技巧,看優(yōu)秀的代碼,我想對我們?nèi)粘叹幋a必然有幫助的。而那些開源的代碼正是千錘百煉的東西,希望和各位共勉。
拿ProtocolListenerWrapper為例子,看源碼的時候發(fā)現(xiàn)它是一個裝飾類的標(biāo)準(zhǔn)實現(xiàn)有一個自身的復(fù)制構(gòu)造函數(shù),把被包裝者復(fù)制進(jìn)來,然后結(jié)合裝飾部分的操作。看下ProtocolListenerWrapper類有這樣的代碼:
public class ProtocolListenerWrapper implements Protocol { private final Protocol protocol; public ProtocolListenerWrapper(Protocol protocol){ if (protocol == null) { throw new IllegalArgumentException("protocol == null"); } this.protocol = protocol; } public int getDefaultPort() { return protocol.getDefaultPort(); } public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) { return protocol.export(invoker); } return new ListenerExporterWrapper<T>(protocol.export(invoker), Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class) .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY))); } public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) { return protocol.refer(type, url); } return new ListenerInvokerWrapper<T>(protocol.refer(type, url), Collections.unmodifiableList( ExtensionLoader.getExtensionLoader(InvokerListener.class) .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY))); } public void destroy() { protocol.destroy(); } }
而我們在ExtensionLoader里找到了這份代碼片段clazz.getConstructor()方法就是去匹配前面提到的裝飾模式用到的方式。
而這些類作為插件會被放入cachedWrapperClasses進(jìn)行緩存。而對這個緩存的使用就是解開listenter調(diào)用實現(xiàn)的鑰匙。
try { clazz.getConstructor(type); Set<Class<?>> wrappers = cachedWrapperClasses; if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet<Class<?>>(); wrappers = cachedWrapperClasses; } wrappers.add(clazz); } catch (NoSuchMethodException e) {
上面也可以看到用一場作為一個判斷邏輯。
ExtensionLoader中g(shù)etExtension(String name)方法中會調(diào)用createExtension(String name)這個方法中將cachedWrapperClasses利用了起來,具體實現(xiàn)就是將被裝飾類實例作為參數(shù)調(diào)用warpper類的自身復(fù)制構(gòu)造函數(shù),這樣就會把被裝飾累包裝起來,從而達(dá)到,當(dāng)有調(diào)用被裝飾類的方法是就可以執(zhí)行到warpper中的邏輯代碼了,實現(xiàn)都是調(diào)用了clazz.getConstructor方法,代碼片段:
Set<Class<?>> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && wrapperClasses.size() > 0) { for (Class<?> wrapperClass : wrapperClasses) { instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } }
再回去看一下ProtocolListenerWrapper,我們可以發(fā)現(xiàn)繼承Protocol中的export方法是對外開放service的入口方法,它返回exporter,代碼中實際是返回了ListenerExporterWrapper,這也是個裝飾類,不過沒有使用上面提到的機制,只是把exporter和listener進(jìn)行類包裝,在構(gòu)造函數(shù)里將listener執(zhí)行。至此我們終于找到了執(zhí)行l(wèi)istener的代碼。
在dubbo的開發(fā)中l(wèi)istener是及其重要的一個擴展口子,在服務(wù)對外時執(zhí)行一些自己想做的事情就些各類繼承ExporterListener
在引用服務(wù)的時候想做些自己的事就寫個類繼承InvokerListener。
另外,ExporterListener為例,發(fā)現(xiàn)他的子類中有一個ExporterListenerAdapter,兩個空方法,代碼:
public abstract class ExporterListenerAdapter implements ExporterListener { public void exported(Exporter<?> exporter) throws RpcException { } public void unexported(Exporter<?> exporter) throws RpcException { } }
這是個技巧吧,剛剛上面提到自己要寫擴展類的時候就不直接繼承ExporterListener了,因為直接繼承接口會強制要求實現(xiàn)兩個方法的,而實際編碼中dubbo的作者應(yīng)該也發(fā)現(xiàn)這兩個方法是完全不同的業(yè)務(wù)時使用,所有我們可以只繼承ExporterListenerAdapter,如此自己的業(yè)務(wù)代碼中就不需要出現(xiàn)一個空方法了。
以上這篇基于dubbo中Listener的實現(xiàn)方法就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java多線程返回值使用示例(callable與futuretask)
這篇文章主要介紹了多線程返回值使用示例(callable與futuretask),需要的朋友可以參考下2014-04-04詳解static 和 final 和 static final區(qū)別
這篇文章主要介紹了static 和 final 和 static final區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04java使用內(nèi)存數(shù)據(jù)庫ssdb的步驟
這篇文章主要介紹了java使用內(nèi)存數(shù)據(jù)庫ssdb的步驟,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12Springboot集成knife4j實現(xiàn)風(fēng)格化API文檔
這篇文章主要介紹了Springboot如何集成knife4j實現(xiàn)風(fēng)格化API文檔,幫助大家更好的使用springboot框架,感興趣的朋友可以了解下2020-12-12