EnableDiscoveryClient没用了?Zookeeper是怎么和springboot配合做服务注册中心的?

Spring Cloud源码分析:EnableDiscoveryClient与EnableEurekaClient的区别(Edgware版本)提到:
在Spring Cloud的Dalston及其之前的版本中:

  1. 从2014年的Spring Cloud 1.0.0.RC1版本开始,官方就推荐使用EnableDiscoveryClient来取代EnableEurekaClient
  2. EnableEurekaClient源码中使用了注解EnableDiscoveryClient,因此如果要使用eureka的注册发现服务,两者功能是一样的;
  3. EnableDiscoveryClient注解在spring.factories配置中通过配置项EurekaDiscoveryClientConfiguration来开启服务注册发现功能;

在Dalston之后的版本中(不含Dalston):

  1. 在spring.factories配置中,配置类EurekaDiscoveryClientConfiguration被配置到springboot的自动配置注解中,与EnableDiscoveryClient注解没有关系了,也就是说只要开启了springboot的自动配置,服务注册发现功能就会启用;
  2. EnableEurekaClient源码中没有使用注解EnableDiscoveryClient,此时EnableEurekaClient已经没用了;

本文来探究一下Zookeeper是怎么做服务注册发现的

老规矩:打开spring.factories

在这里插入图片描述

版本:spring-cloud-zookeeper-discovery-2.1.0.RELEASE.jar

既然EurekaDiscoveryClientConfiguration是Eureka用来做服务注册发现的,那么zookeeper不难猜出是ZookeeperDiscoveryAutoConfiguration

ZookeeperDiscoveryAutoConfiguration源码概览

/*
 * Copyright 2013-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cloud.zookeeper.discovery;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.x.discovery.ServiceDiscovery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
import org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.zookeeper.discovery.dependency.ZookeeperDependencies;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Spencer Gibb
 * @since 1.1.0
 */
@Configuration
@ConditionalOnBean(ZookeeperDiscoveryClientConfiguration.Marker.class)
@ConditionalOnZookeeperDiscoveryEnabled
@AutoConfigureBefore({CommonsClientAutoConfiguration.class, NoopDiscoveryClientAutoConfiguration.class})
@AutoConfigureAfter({ZookeeperDiscoveryClientConfiguration.class})
public class ZookeeperDiscoveryAutoConfiguration {

	@Autowired(required = false)
	private ZookeeperDependencies zookeeperDependencies;

	@Autowired
	private CuratorFramework curator;

	@Bean
	@ConditionalOnMissingBean
	public ZookeeperDiscoveryProperties zookeeperDiscoveryProperties(InetUtils inetUtils) {
		return new ZookeeperDiscoveryProperties(inetUtils);
	}

	@Bean
	@ConditionalOnMissingBean
	// currently means auto-registration is false. That will change when ZookeeperServiceDiscovery is gone
	public ZookeeperDiscoveryClient zookeeperDiscoveryClient(
			ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
			ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
		return new ZookeeperDiscoveryClient(serviceDiscovery, this.zookeeperDependencies,
				zookeeperDiscoveryProperties);
	}

	@Configuration
	@ConditionalOnEnabledHealthIndicator("zookeeper")
	@ConditionalOnClass(Endpoint.class)
	protected static class ZookeeperDiscoveryHealthConfig {
		@Autowired(required = false)
		private ZookeeperDependencies zookeeperDependencies;

		@Bean
		@ConditionalOnMissingBean
		public ZookeeperDiscoveryHealthIndicator zookeeperDiscoveryHealthIndicator(
				CuratorFramework curatorFramework,
				ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
				ZookeeperDiscoveryProperties properties) {
			return new ZookeeperDiscoveryHealthIndicator(curatorFramework,
					serviceDiscovery, this.zookeeperDependencies, properties);
		}
	}

	@Bean
	public ZookeeperServiceWatch zookeeperServiceWatch(ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
		return new ZookeeperServiceWatch(this.curator, zookeeperDiscoveryProperties);
	}

}

1.@ConditionalOnBean(ZookeeperDiscoveryClientConfiguration.Marker.class)

@Configuration
@ConditionalOnProperty(value = "spring.cloud.zookeeper.discovery.enabled", matchIfMissing = true)
public class ZookeeperDiscoveryClientConfiguration {
是否开启zk服务发现功能,默认开启

2.@ConditionalOnZookeeperDiscoveryEnabled

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@ConditionalOnZookeeperEnabled
@ConditionalOnProperty(value = "spring.cloud.zookeeper.discovery.enabled", matchIfMissing = true)
public @interface ConditionalOnZookeeperDiscoveryEnabled {
}

相比上一个注解,增加了新的注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@ConditionalOnProperty(value = "spring.cloud.zookeeper.enabled", matchIfMissing = true)
public @interface ConditionalOnZookeeperEnabled {
}
要求spring.cloud.zookeeper.enabled属性为true,默认为true

3.@AutoConfigureBefore({CommonsClientAutoConfiguration.class, NoopDiscoveryClientAutoConfiguration.class})

要求在NoopDiscoveryClientAutoConfiguration.class和CommonsClientAutoConfiguration.class配置之前进行配置

4.@AutoConfigureAfter({ZookeeperDiscoveryClientConfiguration.class})

要求在ZookeeperDiscoveryClientConfiguration配置之后进行配置

5.ZookeeperDiscoveryAutoConfiguration注册了ZookeeperDiscoveryProperties、ZookeeperDiscoveryClient、ZookeeperServiceWatch、ZookeeperDiscoveryHealthIndicator

ZookeeperDiscoveryProperties

ZookeeperDiscoveryProperties定义了enabled、root、uriSpec、instanceId、instanceHost、instanceIpAddress、preferIpAddress、instancePort、instanceSslPort、register、metadata、initialStatus、order属性

@ConfigurationProperties("spring.cloud.zookeeper.discovery")
public class ZookeeperDiscoveryProperties {

	public static final String DEFAULT_URI_SPEC = "{scheme}://{address}:{port}";

	private InetUtils.HostInfo hostInfo;

	private boolean enabled = true;

	/**
	 * Root Zookeeper folder in which all instances are registered
	 */
	private String root = "/services";

	/**
	 * The URI specification to resolve during service registration in Zookeeper
	 */
	private String uriSpec = DEFAULT_URI_SPEC;

	/** Id used to register with zookeeper. Defaults to a random UUID. */
	private String instanceId;

	/**
	 * Predefined host with which a service can register itself in Zookeeper. Corresponds
	 * to the {code address} from the URI spec.
	 */
	private String instanceHost;

	/** IP address to use when accessing service (must also set preferIpAddress
            to use) */
	private String instanceIpAddress;

	/**
	 * Use ip address rather than hostname during registration
	 */
	private boolean preferIpAddress = false;

	/** Port to register the service under (defaults to listening port) */
	private Integer instancePort;

	/** Ssl port of the registered service. */
	private Integer instanceSslPort;

	/**
	 * Register as a service in zookeeper.
	 */
	private boolean register = true;

	/**
	 * Gets the metadata name/value pairs associated with this instance. This information
	 * is sent to zookeeper and can be used by other instances.
	 */
	private Map<String, String> metadata = new HashMap<>();

	/**
	 * The initial status of this instance (defaults to {@link StatusConstants#STATUS_UP}).
	 */
	private String initialStatus = StatusConstants.STATUS_UP;

	/**
	 * Order of the discovery client used by `CompositeDiscoveryClient` for sorting available clients.
	 */
	private int order = 0;

	// Visible for Testing
	protected ZookeeperDiscoveryProperties() {}

	public ZookeeperDiscoveryProperties(InetUtils inetUtils) {
		this.hostInfo = inetUtils.findFirstNonLoopbackHostInfo();
		this.instanceHost = this.hostInfo.getHostname();
		this.instanceIpAddress = this.hostInfo.getIpAddress();
	}
}

该类中就包括了服务的一些基本信息以及后面创建zk节点的默认根节点("/services")

ZookeeperDiscoveryClient

public class ZookeeperDiscoveryClient implements DiscoveryClient {

	private static final Log log = LogFactory.getLog(ZookeeperDiscoveryClient.class);

	private final ZookeeperDependencies zookeeperDependencies;
	private final ServiceDiscovery<ZookeeperInstance> serviceDiscovery;
	private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;

	public ZookeeperDiscoveryClient(ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
			ZookeeperDependencies zookeeperDependencies,
			ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
		this.serviceDiscovery = serviceDiscovery;
		this.zookeeperDependencies = zookeeperDependencies;
		this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
	}

	@Override
	public String description() {
		return "Spring Cloud Zookeeper Discovery Client";
	}

	private static org.springframework.cloud.client.ServiceInstance createServiceInstance(String serviceId, ServiceInstance<ZookeeperInstance> serviceInstance) {
		return new ZookeeperServiceInstance(serviceId, serviceInstance);
	}

	@Override
	public List<org.springframework.cloud.client.ServiceInstance> getInstances(
			final String serviceId) {
		try {
			if (getServiceDiscovery() == null) {
				return Collections.EMPTY_LIST;
			}
			String serviceIdToQuery = getServiceIdToQuery(serviceId);
			Collection<ServiceInstance<ZookeeperInstance>> zkInstances = getServiceDiscovery().queryForInstances(serviceIdToQuery);
			List<org.springframework.cloud.client.ServiceInstance> instances = new ArrayList<>();
			for (ServiceInstance<ZookeeperInstance> instance : zkInstances) {
				instances.add(createServiceInstance(serviceIdToQuery, instance));
			}
			return instances;
		} catch (KeeperException.NoNodeException e) {
			if (log.isDebugEnabled()) {
				log.debug("Error getting instances from zookeeper. Possibly, no service has registered.", e);
			}
			// this means that nothing has registered as a service yes
			return Collections.emptyList();
		} catch (Exception exception) {
			rethrowRuntimeException(exception);
		}
		return new ArrayList<>();
	}

	private ServiceDiscovery<ZookeeperInstance> getServiceDiscovery() {
		return this.serviceDiscovery;
	}

	private String getServiceIdToQuery(String serviceId) {
		if (this.zookeeperDependencies != null && this.zookeeperDependencies.hasDependencies()) {
			String pathForAlias = this.zookeeperDependencies.getPathForAlias(serviceId);
			return pathForAlias.isEmpty() ? serviceId : pathForAlias;
		}
		return serviceId;
	}

	@Override
	public List<String> getServices() {
		List<String> services = null;
		if (getServiceDiscovery() == null) {
			log.warn("Service Discovery is not yet ready - returning empty list of services");
			return Collections.emptyList();
		}
		try {
			Collection<String> names = getServiceDiscovery().queryForNames();
			if (names == null) {
				return Collections.emptyList();
			}
			services = new ArrayList<>(names);
		}
		catch (KeeperException.NoNodeException e) {
			if (log.isDebugEnabled()) {
				log.debug("Error getting services from zookeeper. Possibly, no service has registered.", e);
			}
			// this means that nothing has registered as a service yes
			return Collections.emptyList();
		}
		catch (Exception e) {
			rethrowRuntimeException(e);
		}
		return services;
	}

	@Override
	public int getOrder() {
		return this.zookeeperDiscoveryProperties.getOrder();
	}
}

ZookeeperDiscoveryClient实现了org.springframework.cloud.client.discovery.DiscoveryClient接口

public interface DiscoveryClient extends Ordered {

	int DEFAULT_ORDER = 0;

	/**
	 * A human-readable description of the implementation, used in HealthIndicator.
	 *
	 * @return The description.
	 */
	String description();

	/**
	 * Gets all ServiceInstances associated with a particular serviceId.
	 *
	 * @param serviceId The serviceId to query.
	 * @return A List of ServiceInstance.
	 */
	List<ServiceInstance> getInstances(String serviceId);

	/**
	 * @return All known service IDs.
	 */
	List<String> getServices();

	/**
	 * Default implementation for getting order of discovery clients.
	 *
	 * @return order
	 */
	@Override
	default int getOrder() {
		return DEFAULT_ORDER;
	}
}

ZookeeperDiscoveryClient的具体实现:(对应的还有EnableDiscoveryClient等等)

getInstances使用curator的ServiceDiscovery.queryForInstances获取服务实例信息,然后转换为org.springframework.cloud.client.ServiceInstance类型;
for (ServiceInstance<ZookeeperInstance> instance : zkInstances) {
	instances.add(createServiceInstance(serviceIdToQuery, instance));
}
			
private static org.springframework.cloud.client.ServiceInstance createServiceInstance(String serviceId, ServiceInstance<ZookeeperInstance> serviceInstance) {
		return new ZookeeperServiceInstance(serviceId, serviceInstance);
}
	
public class ZookeeperServiceInstance implements ServiceInstance 
getServices则是使用curator的ServiceDiscovery.queryForNames获取服务名信息

关于curator

ZookeeperDiscoveryHealthIndicator

public class ZookeeperDiscoveryHealthIndicator implements DiscoveryHealthIndicator {

	private static final Log log = LogFactory
			.getLog(ZookeeperDiscoveryHealthIndicator.class);

	private CuratorFramework curatorFramework;
	private ServiceDiscovery<ZookeeperInstance> serviceDiscovery;
	private final ZookeeperDependencies zookeeperDependencies;
	private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;

	public ZookeeperDiscoveryHealthIndicator(CuratorFramework curatorFramework,
			ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
			ZookeeperDependencies zookeeperDependencies,
			ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
		this.curatorFramework = curatorFramework;
		this.serviceDiscovery = serviceDiscovery;
		this.zookeeperDependencies = zookeeperDependencies;
		this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
	}

	@Override
	public String getName() {
		return "zookeeper";
	}

	@Override
	public Health health() {
		Health.Builder builder = Health.unknown();
		try {
			Iterable<ServiceInstance<ZookeeperInstance>> allInstances =
					new ZookeeperServiceInstances(this.curatorFramework,
						this.serviceDiscovery, this.zookeeperDependencies,
						this.zookeeperDiscoveryProperties);
			builder.up().withDetail("services", allInstances);
		}
		catch (Exception e) {
			log.error("Error", e);
			builder.down(e);
		}

		return builder.build();
	}

}

ZookeeperDiscoveryHealthIndicator实现了DiscoveryHealthIndicator接口,其health方法创建ZookeeperServiceInstances

ZookeeperServiceInstances

public class ZookeeperServiceInstances
		implements Iterable<ServiceInstance<ZookeeperInstance>> {

	private static final Log log = LogFactory.getLog(ZookeeperServiceInstances.class);

	private ServiceDiscovery<ZookeeperInstance> serviceDiscovery;
	private final ZookeeperDependencies zookeeperDependencies;
	private final ZookeeperDiscoveryProperties zookeeperDiscoveryProperties;
	private final List<ServiceInstance<ZookeeperInstance>> allInstances;
	private final CuratorFramework curator;

	public ZookeeperServiceInstances(CuratorFramework curator,
			ServiceDiscovery<ZookeeperInstance> serviceDiscovery,
			ZookeeperDependencies zookeeperDependencies,
			ZookeeperDiscoveryProperties zookeeperDiscoveryProperties) {
		this.curator = curator;
		this.serviceDiscovery = serviceDiscovery;
		this.zookeeperDependencies = zookeeperDependencies;
		this.zookeeperDiscoveryProperties = zookeeperDiscoveryProperties;
		this.allInstances = getZookeeperInstances();
	}

	private List<ServiceInstance<ZookeeperInstance>> getZookeeperInstances() {
		ArrayList<ServiceInstance<ZookeeperInstance>> allInstances = new ArrayList<>();
		try {
			Collection<String> namesToQuery = getNamesToQuery();
			if (log.isDebugEnabled()) {
				log.debug("Querying the following names [" + namesToQuery + "]");
			}
			for (String name : namesToQuery) {
				allInstances.addAll(nestedInstances(allInstances, name));
			}
			return allInstances;
		}
		catch (Exception e) {
			log.debug("Exception occurred while trying to build the list of instances",
					e);
			return allInstances;
		}
	}

	private List<ServiceInstance<ZookeeperInstance>> nestedInstances(
			List<ServiceInstance<ZookeeperInstance>> accumulator, String name)
			throws Exception {
		String parentPath = prepareQueryName(name);
		Collection<ServiceInstance<ZookeeperInstance>> childrenInstances = tryToGetInstances(
				parentPath);
		if (childrenInstances != null) {
			return convertCollectionToList(childrenInstances);
		}
		try {
			List<String> children = this.curator.getChildren().forPath(parentPath);
			return iterateOverChildren(accumulator, parentPath, children);
		} catch (Exception e) {
			if (log.isTraceEnabled()) {
				log.trace("Exception occurred while trying to retrieve children of [" + parentPath + "]", e);
			}
			return injectZookeeperServiceInstances(accumulator, parentPath);
		}
	}

	private String prepareQueryName(String name) {
		String root = this.zookeeperDiscoveryProperties.getRoot();
		return name.startsWith(root) ? name : root + name;
	}

	private Collection<ServiceInstance<ZookeeperInstance>> tryToGetInstances(
			String path) {
		try {
			return getServiceDiscovery()
					.queryForInstances(getPathWithoutRoot(path));
		}
		catch (Exception e) {
			log.trace("Exception occurred while trying to retrieve instances of [" + path
					+ "]", e);
			return null;
		}
	}

	private ServiceDiscovery<ZookeeperInstance> getServiceDiscovery() {
		return this.serviceDiscovery;
	}

	private String getPathWithoutRoot(String path) {
		return path.substring(this.zookeeperDiscoveryProperties.getRoot().length());
	}

	private List<ServiceInstance<ZookeeperInstance>> injectZookeeperServiceInstances(
			List<ServiceInstance<ZookeeperInstance>> accumulator, String name)
			throws Exception {
		Collection<ServiceInstance<ZookeeperInstance>> instances = getServiceDiscovery().queryForInstances(name);
		accumulator.addAll(convertCollectionToList(instances));
		return accumulator;
	}

	private List<ServiceInstance<ZookeeperInstance>> convertCollectionToList(
			Collection<ServiceInstance<ZookeeperInstance>> instances) {
		List<ServiceInstance<ZookeeperInstance>> serviceInstances = new ArrayList<>();
		for (ServiceInstance<ZookeeperInstance> instance : instances) {
			serviceInstances.add(instance);
		}
		return serviceInstances;
	}

	private List<ServiceInstance<ZookeeperInstance>> iterateOverChildren(
			List<ServiceInstance<ZookeeperInstance>> accumulator, String parentPath,
			List<String> children) throws Exception {
		List<ServiceInstance<ZookeeperInstance>> lists = new ArrayList<>();
		for (String child : children) {
			lists.addAll(nestedInstances(accumulator, parentPath + "/" + child));
		}
		return lists;
	}

	private Collection<String> getNamesToQuery() throws Exception {
		if (this.zookeeperDependencies == null) {
			if (log.isDebugEnabled()) {
				log.debug("Using direct name resolution instead of dependency based one");
			}
			List<String> names = new ArrayList<>();
			for (String name : getServiceDiscovery().queryForNames()) {
				names.add(sanitize(name));
			}
			return names;
		}
		if (log.isDebugEnabled()) {
			log.debug("Using dependency based names to query");
		}
		return this.zookeeperDependencies.getDependencyNames();
	}

	@Override
	public Iterator<ServiceInstance<ZookeeperInstance>> iterator() {
		return this.allInstances.iterator();
	}

}

ZookeeperServiceInstances的构造器会调用getZookeeperInstances拉取ServiceInstance
ServiceInstance记录id,port,address等信息

public class ServiceInstance<T>
{
    private final String        name;
    private final String        id;
    private final String        address;
    private final Integer       port;
    private final Integer       sslPort;
    private final T             payload;
    private final long          registrationTimeUTC;
    private final ServiceType   serviceType;
    private final UriSpec       uriSpec;
    private final boolean       enabled;
}

ZookeeperServiceWatch

public class ZookeeperServiceWatch implements
		ApplicationListener<InstanceRegisteredEvent<?>>, TreeCacheListener,
		ApplicationEventPublisherAware {

	private final CuratorFramework curator;
	private final ZookeeperDiscoveryProperties properties;
	private final AtomicLong cacheChange = new AtomicLong(0);
	private ApplicationEventPublisher publisher;
	private TreeCache cache;

	public ZookeeperServiceWatch(CuratorFramework curator,
			ZookeeperDiscoveryProperties properties) {
		this.curator = curator;
		this.properties = properties;
	}

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
		this.publisher = publisher;
	}

	public TreeCache getCache() {
		return this.cache;
	}

	@Override
	public void onApplicationEvent(InstanceRegisteredEvent<?> event) {
		this.cache = TreeCache.newBuilder(this.curator, this.properties.getRoot()).build();
		this.cache.getListenable().addListener(this);
		try {
			this.cache.start();
		}
		catch (Exception e) {
			ReflectionUtils.rethrowRuntimeException(e);
		}
	}

	@PreDestroy
	public void stop() throws Exception {
		if (this.cache != null) {
			this.cache.close();
		}
	}

	@Override
	public void childEvent(CuratorFramework client, TreeCacheEvent event) throws Exception {
		if (event.getType().equals(TreeCacheEvent.Type.NODE_ADDED)
				|| event.getType().equals(TreeCacheEvent.Type.NODE_REMOVED)
				|| event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
			long newCacheChange = this.cacheChange.incrementAndGet();
			this.publisher.publishEvent(new HeartbeatEvent(this, newCacheChange));
		}
	}
}

ZookeeperServiceWatch实现了ApplicationListener、TreeCacheListener、ApplicationEventPublisherAware接口;其childEvent方法在event类型是NODE_ADDED、NODE_REMOVED、NODE_UPDATED类型时会发布HeartbeatEvent事件

至此,ZookeeperDiscoveryAutoConfiguration这个配置类分析完毕为服务发现提供基础能力,spring.factories中我们还注意到一个配置类:ZookeeperAutoServiceRegistrationAutoConfiguration,而这里是真正执行服务注册的地方

ZookeeperAutoServiceRegistrationAutoConfiguration

zookeeper服务自动注册自动配置类

@Configuration
@ConditionalOnMissingBean(type = "org.springframework.cloud.zookeeper.discovery.ZookeeperLifecycle")
@ConditionalOnZookeeperDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
@AutoConfigureAfter( { ZookeeperServiceRegistryAutoConfiguration.class} )
@AutoConfigureBefore( {AutoServiceRegistrationAutoConfiguration.class,ZookeeperDiscoveryAutoConfiguration.class} )
public class ZookeeperAutoServiceRegistrationAutoConfiguration {

	@Bean
	public ZookeeperAutoServiceRegistration zookeeperAutoServiceRegistration(
			ZookeeperServiceRegistry registry, ZookeeperRegistration registration,
			ZookeeperDiscoveryProperties properties) {
		return new ZookeeperAutoServiceRegistration(registry, registration, properties);
	}

	@Bean
	@ConditionalOnMissingBean(ZookeeperRegistration.class)
	public ServiceInstanceRegistration serviceInstanceRegistration(
			ApplicationContext context, ZookeeperDiscoveryProperties properties) {
		String appName = context.getEnvironment().getProperty("spring.application.name",
				"application");
		String host = properties.getInstanceHost();
		if (!StringUtils.hasText(host)) {
			throw new IllegalStateException("instanceHost must not be empty");
		}

		ZookeeperInstance zookeeperInstance = new ZookeeperInstance(context.getId(),
				appName, properties.getMetadata());
		RegistrationBuilder builder = ServiceInstanceRegistration.builder().address(host)
				.name(appName).payload(zookeeperInstance)
				.uriSpec(properties.getUriSpec());

		if (properties.getInstanceSslPort() != null) {
			builder.sslPort(properties.getInstanceSslPort());
		}
		if (properties.getInstanceId() != null) {
			builder.id(properties.getInstanceId());
		}


		// TODO add customizer?

		return builder.build();
	}

}

服务启动之后,会先在这个类中根据application.yml文件中的配置内容生成一个ServiceInstanceRegistration服务实例注册类;

这个类中包含了两个对象:

ServiceInstance服务实例对象
ServiceInstanceBuilder服务实例构造对象

ServiceInstance服务实例中的属性就包含了服务的ip,port,name以及zk节点属性等属性;后面会根据这些信息创建一个zk节点

public class ServiceInstance<T> {
    private final String name;                   服务名
    private final String id;                     服务id
    private final String address;                服务地址(不填默认取主机名)
    private final Integer port;                  服务端口
    private final Integer sslPort;               https协议端口
    private final T payload;                     其实就是zookeeperinstance对象
    private final long registrationTimeUTC;      注册时间
    private final ServiceType serviceType;       生成的zk节点属性(默认是EPHEMERAL)
    private final UriSpec uriSpec;               包括了ip+端口
    private final boolean enabled;               该服务实例是否可用
}

ZookeeperInstance zk实例中包含了id,name以及metadata属性

public class ZookeeperInstance {
    private String id;
    private String name;
    private Map<String, String> metadata = new HashMap();
}

ZookeeperAutoServiceRegistration

ZookeeperAutoServiceRegistration zk节点自动注册服务;

@Bean
	public ZookeeperAutoServiceRegistration zookeeperAutoServiceRegistration(
			ZookeeperServiceRegistry registry, ZookeeperRegistration registration,
			ZookeeperDiscoveryProperties properties) {
		return new ZookeeperAutoServiceRegistration(registry, registration, properties);
	}

看一下这个类

public ZookeeperAutoServiceRegistration(ZookeeperServiceRegistry registry,
											ZookeeperRegistration registration,
											ZookeeperDiscoveryProperties properties) {
		this(registry, registration, properties, null);
}



public ZookeeperAutoServiceRegistration(ZookeeperServiceRegistry registry,
											ZookeeperRegistration registration,
											ZookeeperDiscoveryProperties properties,
											AutoServiceRegistrationProperties arProperties) {
		super(registry, arProperties);
		this.registration = registration;
		this.properties = properties;
		if (this.properties.getInstancePort() != null) {
			this.registration.setPort(this.properties.getInstancePort());
		}
	}

我们需要关注的是该类下有一个register()方法

protected void register() {
		if (!this.properties.isRegister()) {
			log.debug("Registration disabled.");
			return;
		}
		if (this.registration.getPort() == 0) {
			this.registration.setPort(getPort().get());
		}
		super.register();
	}

跟踪到父类

protected void register() {
		this.serviceRegistry.register(getRegistration());
	}

定位到org.springframework.cloud.zookeeper.serviceregistry.ZookeeperServiceRegistry

public void register(ZookeeperRegistration registration) {
		try {
			getServiceDiscovery().registerService(registration.getServiceInstance());
		} catch (Exception e) {
			rethrowRuntimeException(e);
		}
	}

核心逻辑

@VisibleForTesting
    protected void internalRegisterService(ServiceInstance<T> service) throws Exception
    {
        byte[] bytes = serializer.serialize(service);
        String path = pathForInstance(service.getName(), service.getId());

        final int MAX_TRIES = 2;
        boolean isDone = false;
        for ( int i = 0; !isDone && (i < MAX_TRIES); ++i )
        {
            try
            {
				CreateMode mode;
				switch (service.getServiceType()) {
				case DYNAMIC:
					mode = CreateMode.EPHEMERAL;
					break;
				case DYNAMIC_SEQUENTIAL:
					mode = CreateMode.EPHEMERAL_SEQUENTIAL;
					break;
				default:
					mode = CreateMode.PERSISTENT;
					break;
				}
                client.create().creatingParentContainersIfNeeded().withMode(mode).forPath(path, bytes);
                isDone = true;
            }
            catch ( KeeperException.NodeExistsException e )
            {
                client.delete().forPath(path);  // must delete then re-create so that watchers fire
            }
        }
    }

在这个方法中首先判断得出节点的属性,然后通过CuratorFramework来创建zk节点;至此服务就注册到zk上面了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值