苏州网站seo服务上海企业seo
总览
学习 Dubbo 的服务发现机制,可以从以下几方面入手:
- 注册中心的配置
- 服务的注册
- 客户端拉取服务列表
- 服务列表的本地缓存
- 服务提供者列表变更的监听机制
- 服务发现的接口设计
注册中心的配置
Dubbo 通过解析用户配置决定使用的注册中心。比如用户配置了 zookeeper://127.0.0.1:2181,Dubbo 在导出服务时解析出 name = zookeeper,便拿着这个名字到 ExtensionLoader 加载得到 ZookeeperServiceDiscoveryFactory,该工厂类生产出 ZookeeperServiceDiscovery,后续 ServiceDiscoveryRegistry 便可以通过调用 ZookeeperServiceDiscovery 的 doRegister 方法注册服务。
服务的注册
Spring 执行 refresh 方法后会触发 Dubbo 将服务注册到注册中心。
Spring 的 AbstractApplicationContext 执行 refresh 方法返回前,会发布 ContextRefreshedEvent, DubboBootstrapApplicationListener 接收到 ContextRefreshedEvent 后,会初始化并导出服务,最后将服务注册到注册中心。
/*** An ApplicationListener to control Dubbo application.*/
public class DubboDeployApplicationListenerimplements ApplicationListener<ApplicationContextEvent>, ApplicationContextAware, Ordered {@Overridepublic void onApplicationEvent(ApplicationContextEvent event) {if (nullSafeEquals(applicationContext, event.getSource())) {if (event instanceof ContextRefreshedEvent) {onContextRefreshedEvent((ContextRefreshedEvent) event);}...}}private void onContextRefreshedEvent(ContextRefreshedEvent event) {ModuleDeployer deployer = moduleModel.getDeployer();Assert.notNull(deployer, "Module deployer is null");Object singletonMutex = LockUtils.getSingletonMutex(applicationContext);// start moduleFuture future = null;synchronized (singletonMutex) {future = deployer.start();}...}
}
ModuleDeployer 在 start 方法中调用了 registerServices 方法,完成了服务的注册。其调用链如下:
ModuleDeployer.registerServices -> ModuleDeployer.registerServiceInternal
-> ServiceConfigBase.register -> Exporter.register
其中,ModuleDeployer.registerServiceInternal 遍历 configManager 中的每一个服务,逐个对它们进行注册。
Exporter.register 实际调用的类视注册中心的不同而不同,以 ZooKeeper 为例,通过模版方法实现服务注册:
public abstract class FailbackRegistry extends AbstractRegistry {@Overridepublic void register(URL url) {if (!shouldRegister(url)) {return;}super.register(url);removeFailedRegistered(url);removeFailedUnregistered(url);try {// Sending a registration request to the server sidedoRegister(url);} catch (Exception e) {Throwable t = e;// If the startup detection is opened, the Exception is thrown directly.boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)&& url.getParameter(Constants.CHECK_KEY, true)&& (url.getPort() != 0);boolean skipFailback = t instanceof SkipFailbackWrapperException;if (check || skipFailback) {if (skipFailback) {t = t.getCause();}throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: "+ t.getMessage(),t);} else {logger.error(INTERNAL_ERROR,"unknown error in registry module","","Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(),t);}// Record a failed registration request to a failed list, retry regularlyaddFailedRegistered(url);}}
}
doRegister 仅仅是在 Zookeeper 创建一个 ZNode(Zookeeper 文件系统中的节点):
@Overridepublic void doRegister(URL url) {try {checkDestroyed();zkClient.create(toUrlPath(url), url.getParameter(DYNAMIC_KEY, true), true);} catch (Throwable e) {throw new RpcException("Failed to register " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e);}}