既然有dubbo bean的export功能,那么就有dubbo bean的unexport功能,如果我們也將dubbo bean的unexport的功能搞清楚,我們可以設計一個非常牛的debug小插件,這個留到后面講。
ServiceBean的父類ServiceConfig提供了注銷bean的方法,如下
Class ServiceConfig
public synchronized void unexport() {
if (!exported) {
return;
}
if (unexported) {
return;
}
if (!exporters.isEmpty()) {
for (Exporter<?> exporter : exporters) {
try {
exporter.unexport();
} catch (Throwable t) {
logger.warn("unexpected err when unexport" + exporter, t);
}
}
exporters.clear();
}
unexported = true;
}
其中exporters是在上一篇介紹的暴露的兩個export,如下圖

image.png
我們接下來看下每個exporter具體是怎么unexport的,對一個類型為InjvmExporter
Class InjvmExporter
public void unexport() {
//調(diào)用父類的unexport 其實啥也沒做
super.unexport();
//在本地緩存中remove掉
exporterMap.remove(key);
}
針對第二個exporter,調(diào)用unexport進入到RegistryProtocol
Class RegistryProtocol
Registry registry = RegistryProtocol.INSTANCE.getRegistry(originInvoker);
try {
//這個registry真實是ZookeeperRegistry
registry.unregister(registerUrl);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
try {
NotifyListener listener = RegistryProtocol.INSTANCE.overrideListeners.remove(subscribeUrl);
registry.unsubscribe(subscribeUrl, listener);
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
executor.submit(new Runnable() {
@Override
public void run() {
try {
int timeout = ConfigUtils.getServerShutdownTimeout();
if (timeout > 0) {
logger.info("Waiting " + timeout + "ms for registry to notify all consumers before unexport. Usually, this is called when you use dubbo API");
Thread.sleep(timeout);
}
exporter.unexport();
} catch (Throwable t) {
logger.warn(t.getMessage(), t);
}
}
});
}
其中ZookeeperRegistry的unregister是在父類FailbackRegistry里面實現(xiàn)的,等于說zk的操作都是默認是failback(失敗重試機制),代碼如下(省略了不相關的代碼)
public void unregister(URL url) {
//在父類緩存中將緩存的url刪除
super.unregister(url);
// Sending a cancellation request to the server side
doUnregister(url);
}
如下,使用zkClient將
Class ZookeeperRegistry
protected void doUnregister(URL url) {
try {
//將注冊信息在zk上進行刪除,這樣消費者監(jiān)聽到變化之后,將不再調(diào)用此本地服務
zkClient.delete(toUrlPath(url));
} catch (Throwable e) {
throw new RpcException("Failed to unregister " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
同時對取消對該bean的配置信息的監(jiān)聽,如下
NotifyListener listener = RegistryProtocol.INSTANCE.overrideListeners.remove(subscribeUrl);
registry.unsubscribe(subscribeUrl, listener);
在我的pc上,其實就是取消對/dubbo/com.**.wms.dubbo.service.OrderCancelService/configurators路徑和其子節(jié)點的監(jiān)聽。
經(jīng)過如上的操作,該dubbo bean在zk上的信息都被清除了,現(xiàn)在需要清除本地的暴露信息,其實也是刪除本地的緩存信息,大家有信息可以去看下。源碼比較簡單。
dubbo bean的unexport主要影響的是消費端,消費端檢測到zk上面的注冊信息發(fā)生變化之后,也會實時的更新本地的緩存信息。后面我們會繼續(xù)的對dubbo的消費端的源碼進行分析
再貼一下取消的流程圖

image.png