At present, dubbo supports a variety of registration centers: Zookeeper, Redis, Simple, Multicast, Etcd3.
This article analyzes how dubbo integrates Zookeeper to register and subscribe services when Zookeeper is used as the registration center.
First, Dubbo registers the service with Zookeeper, and the directory structure is as follows: (registration interface name: com.bob.dubbo.service.CityDubboService)
When the consumer and provider services are started, format their own URL into a string, and then register it under the corresponding node of zookeeper as a temporary node. After disconnection, the node will be deleted. When the consumer starts, it will not only subscribe to the service, but also register its own URL into zookeeper;
ZookeeperRegistry
ZookeeperRegistry: the main interaction classes between dubbo and zookeeper have been analyzed in combination with the source code. First, let's look at the doSubcribe() method:
@Override public void doSubscribe(final URL url, final NotifyListener listener) { try { // Handle all subscriptions initiated by the service layer, such as those in the monitoring center if (Constants.ANY_VALUE.equals(url.getServiceInterface())) { String root = toRootPath(); ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url); if (listeners == null) { zkListeners.putIfAbsent(url, new ConcurrentHashMap<>()); listeners = zkListeners.get(url); } ChildListener zkListener = listeners.get(listener); if (zkListener == null) { listeners.putIfAbsent(listener, (parentPath, currentChilds) -> { for (String child : currentChilds) { child = URL.decode(child); if (!anyServices.contains(child)) { anyServices.add(child); subscribe(url.setPath(child).addParameters(Constants.INTERFACE_KEY, child, Constants.CHECK_KEY, String.valueOf(false)), listener); } } }); zkListener = listeners.get(listener); } zkClient.create(root, false); List<String> services = zkClient.addChildListener(root, zkListener); if (services != null && !services.isEmpty()) { for (String service : services) { service = URL.decode(service); anyServices.add(service); subscribe(url.setPath(service).addParameters(Constants.INTERFACE_KEY, service, Constants.CHECK_KEY, String.valueOf(false)), listener); } } // Process subscriptions initiated by the specified service layer, such as those of service consumers } else { List<URL> urls = new ArrayList<>(); // Circular classification array, router, configurator, provider for (String path : toCategoriesPath(url)) { // Get the listener set corresponding to url ConcurrentMap<NotifyListener, ChildListener> listeners = zkListeners.get(url); if (listeners == null) {// No, create zkListeners.putIfAbsent(url, new ConcurrentHashMap<>()); listeners = zkListeners.get(url); } // Get ChildListener object ChildListener zkListener = listeners.get(listener); if (zkListener == null) {// No listener exists for subdirectory to create ChildListener object // Subscribe to the parent directory. When any child node changes, this callback function will be triggered and the notify() method in the listener will be called back listeners.putIfAbsent(listener, (parentPath, currentChilds) -> ZookeeperRegistry.this.notify(url, listener, toUrlsWithEmpty(url, parentPath, currentChilds))); zkListener = listeners.get(listener); } // Initiate subscription to Zookeeper, PATH node, and return all child elements under this node PATH: / root node / interface full name / providers, such as / dubbo/com.bob.service.CityService/providers zkClient.create(path, false); List<String> children = zkClient.addChildListener(path, zkListener); if (children != null) { urls.addAll(toUrlsWithEmpty(url, path, children)); } } // When the first full data acquisition is completed, call the 'notify(...)' method and call back the NotifyListener. In this step, instantiate the Invoker from the connection Provider notify(url, listener, urls); } } catch (Throwable e) { throw new RpcException("Failed to subscribe " + url + " to zookeeper " + getUrl() + ", cause: " + e.getMessage(), e); } }