既然有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() {
//调用父类的unexport 其实啥也没做
super.unexport();
//在本地缓存中remove掉
exporterMap.remove(key);
}
针对第二个exporter,调用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里面实现的,等于说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上进行删除,这样消费者监听到变化之后,将不再调用此本地服务
zkClient.delete(toUrlPath(url));
} catch (Throwable e) {
throw new RpcException("Failed to unregister " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);
}
}
同时对取消对该bean的配置信息的监听,如下
NotifyListener listener = RegistryProtocol.INSTANCE.overrideListeners.remove(subscribeUrl);
registry.unsubscribe(subscribeUrl, listener);
在我的pc上,其实就是取消对/dubbo/com.**.wms.dubbo.service.OrderCancelService/configurators路径和其子节点的监听。
经过如上的操作,该dubbo bean在zk上的信息都被清除了,现在需要清除本地的暴露信息,其实也是删除本地的缓存信息,大家有信息可以去看下。源码比较简单。
dubbo bean的unexport主要影响的是消费端,消费端检测到zk上面的注册信息发生变化之后,也会实时的更新本地的缓存信息。后面我们会继续的对dubbo的消费端的源码进行分析
再贴一下取消的流程图

image.png