[spring-cloud: 服务发现]-源码解析

发布于:2025-08-04 ⋅ 阅读:(15) ⋅ 点赞:(0)

DiscoveryClient

DiscoveryClient 接口定义了常见的服务发现操作,如获取服务实例、获取所有服务ID、验证客户端可用性等,通常用于 Eureka 或 Consul 等服务发现框架。

public interface DiscoveryClient extends Ordered {

	/**
	 * Default order of the discovery client.
	 */
	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();

	/**
	 * Can be used to verify the client is valid and able to make calls.
	 * <p>
	 * A successful invocation with no exception thrown implies the client is able to make
	 * calls.
	 * <p>
	 * The default implementation simply calls {@link #getServices()} - client
	 * implementations can override with a lighter weight operation if they choose to.
	 */
	default void probe() {
		getServices();
	}

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

}

Simple

1. SimpleDiscoveryClientAutoConfiguration

SimpleDiscoveryClientAutoConfiguration 是 Spring Boot 自动配置类,基于配置文件属性创建一个简单的服务发现客户端。

/**
 * Spring Boot auto-configuration for simple properties-based discovery client.
 *
 * @author Biju Kunjummen
 * @author Charu Covindane
 */
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore({ CommonsClientAutoConfiguration.class })
public class SimpleDiscoveryClientAutoConfiguration implements ApplicationListener<WebServerInitializedEvent> {

	private ServerProperties server;

	private InetUtils inet;

	private int port = 0;

	private SimpleDiscoveryProperties simple = new SimpleDiscoveryProperties();

	@Autowired(required = false)
	public void setServer(ServerProperties server) {
		this.server = server;
	}

	@Autowired
	public void setInet(InetUtils inet) {
		this.inet = inet;
	}

	@Bean
	@ConditionalOnMissingBean
	public SimpleDiscoveryProperties simpleDiscoveryProperties(
			@Value("${spring.application.name:application}") String serviceId) {
		simple.getLocal().setServiceId(serviceId);
		simple.getLocal().setHost(inet.findFirstNonLoopbackHostInfo().getHostname());
		simple.getLocal().setPort(findPort());
		return simple;
	}

	@Bean
	@Order
	public DiscoveryClient simpleDiscoveryClient(SimpleDiscoveryProperties properties) {
		return new SimpleDiscoveryClient(properties);
	}

	private int findPort() {
		if (port > 0) {
			return port;
		}
		if (server != null && server.getPort() != null && server.getPort() > 0) {
			return server.getPort();
		}
		return 8080;
	}

	@Override
	public void onApplicationEvent(WebServerInitializedEvent webServerInitializedEvent) {
		port = webServerInitializedEvent.getWebServer().getPort();
		if (port > 0) {
			simple.getLocal().setHost(inet.findFirstNonLoopbackHostInfo().getHostname());
			simple.getLocal().setPort(port);
		}
	}

}

2. SimpleDiscoveryClient

SimpleDiscoveryClient 是一个简单的 DiscoveryClient 实现,使用属性文件作为服务实例的来源,提供获取服务实例和服务列表的功能。

/**
 * A {@link org.springframework.cloud.client.discovery.DiscoveryClient} that will use the
 * properties file as a source of service instances.
 *
 * @author Biju Kunjummen
 * @author Olga Maciaszek-Sharma
 * @author Charu Covindane
 */
public class SimpleDiscoveryClient implements DiscoveryClient {

	private SimpleDiscoveryProperties simpleDiscoveryProperties;

	public SimpleDiscoveryClient(SimpleDiscoveryProperties simpleDiscoveryProperties) {
		this.simpleDiscoveryProperties = simpleDiscoveryProperties;
	}

	@Override
	public String description() {
		return "Simple Discovery Client";
	}

	@Override
	public List<ServiceInstance> getInstances(String serviceId) {
		List<ServiceInstance> serviceInstances = new ArrayList<>();
		List<DefaultServiceInstance> serviceInstanceForService = this.simpleDiscoveryProperties.getInstances()
				.get(serviceId);
		if (serviceInstanceForService != null) {
			serviceInstances.addAll(serviceInstanceForService);
		}
		return serviceInstances;
	}

	@Override
	public List<String> getServices() {
		return new ArrayList<>(this.simpleDiscoveryProperties.getInstances().keySet());
	}

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

}

Composite

1. CompositeDiscoveryClientAutoConfiguration

CompositeDiscoveryClientAutoConfiguration 是一个自动配置类,负责创建并注入 CompositeDiscoveryClient,将多个 DiscoveryClient 合并成一个客户端。

/**
 * Auto-configuration for composite discovery client.
 *
 * @author Biju Kunjummen
 */
@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(SimpleDiscoveryClientAutoConfiguration.class)
public class CompositeDiscoveryClientAutoConfiguration {

	@Bean
	@Primary
	public CompositeDiscoveryClient compositeDiscoveryClient(List<DiscoveryClient> discoveryClients) {
		return new CompositeDiscoveryClient(discoveryClients);
	}

}

2. CompositeDiscoveryClient

CompositeDiscoveryClient 是一个将多个 DiscoveryClient 组合在一起的客户端,它依次查询各个客户端获取服务实例,确保高可用性和灵活性。

public class CompositeDiscoveryClient implements DiscoveryClient {

	private final List<DiscoveryClient> discoveryClients;

	public CompositeDiscoveryClient(List<DiscoveryClient> discoveryClients) {
		AnnotationAwareOrderComparator.sort(discoveryClients);
		this.discoveryClients = discoveryClients;
	}

	@Override
	public String description() {
		return "Composite Discovery Client";
	}

	@Override
	public List<ServiceInstance> getInstances(String serviceId) {
		if (this.discoveryClients != null) {
			for (DiscoveryClient discoveryClient : this.discoveryClients) {
				List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
				if (instances != null && !instances.isEmpty()) {
					return instances;
				}
			}
		}
		return Collections.emptyList();
	}

	@Override
	public List<String> getServices() {
		LinkedHashSet<String> services = new LinkedHashSet<>();
		if (this.discoveryClients != null) {
			for (DiscoveryClient discoveryClient : this.discoveryClients) {
				List<String> serviceForClient = discoveryClient.getServices();
				if (serviceForClient != null) {
					services.addAll(serviceForClient);
				}
			}
		}
		return new ArrayList<>(services);
	}

	@Override
	public void probe() {
		if (this.discoveryClients != null) {
			for (DiscoveryClient discoveryClient : this.discoveryClients) {
				discoveryClient.probe();
			}
		}
	}

	public List<DiscoveryClient> getDiscoveryClients() {
		return this.discoveryClients;
	}

}

Nacos

Nacos是一个开源的动态服务发现、配置管理和服务管理平台,广泛用于微服务架构中的服务治理与配置管理。

1. NacosDiscoveryAutoConfiguration

NacosDiscoveryAutoConfiguration 类是一个 Spring 配置类,用于自动配置 Nacos 服务发现功能。它在 Nacos 服务发现启用时创建所需的 NacosDiscoveryPropertiesNacosServiceDiscovery Bean,并确保在没有其他相关 Bean 的情况下提供默认配置。

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosDiscoveryAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public NacosDiscoveryProperties nacosProperties() {
		return new NacosDiscoveryProperties();
	}

	@Bean
	@ConditionalOnMissingBean
	public NacosServiceDiscovery nacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) {
		return new NacosServiceDiscovery(discoveryProperties, nacosServiceManager);
	}

}

2. NacosDiscoveryClientConfiguration

NacosDiscoveryClientConfiguration 类用于配置和初始化 Nacos 服务发现客户端及其相关功能,如 DiscoveryClientNacosWatch

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnBlockingDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class })
@AutoConfigureAfter(NacosDiscoveryAutoConfiguration.class)
public class NacosDiscoveryClientConfiguration {

	@Bean
	public DiscoveryClient nacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
		return new NacosDiscoveryClient(nacosServiceDiscovery);
	}

	/**
	 * NacosWatch is no longer enabled by default .
	 * see https://github.com/alibaba/spring-cloud-alibaba/issues/2868
	 */
	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled", matchIfMissing = false)
	public NacosWatch nacosWatch(NacosServiceManager nacosServiceManager,
			NacosDiscoveryProperties nacosDiscoveryProperties) {
		return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties);
	}

}

3. NacosDiscoveryClient

NacosDiscoveryClient 实现了 DiscoveryClient 接口,通过与 Nacos 服务发现交互,提供获取服务实例和服务列表的功能,同时支持故障容错。

public class NacosDiscoveryClient implements DiscoveryClient {

	private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryClient.class);

	public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";

	private NacosServiceDiscovery serviceDiscovery;

	@Value("${spring.cloud.nacos.discovery.failure-tolerance-enabled:false}")
	private boolean failureToleranceEnabled;

	public NacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
		this.serviceDiscovery = nacosServiceDiscovery;
	}

	@Override
	public String description() {
		return DESCRIPTION;
	}

	@Override
	public List<ServiceInstance> getInstances(String serviceId) {
		try {
			return Optional.of(serviceDiscovery.getInstances(serviceId))
					.map(instances -> {
						ServiceCache.setInstances(serviceId, instances);
						return instances;
					}).get();
		}
		catch (Exception e) {
			if (failureToleranceEnabled) {
				return ServiceCache.getInstances(serviceId);
			}
			throw new RuntimeException(
					"Can not get hosts from nacos server. serviceId: " + serviceId, e);
		}
	}

	@Override
	public List<String> getServices() {
		try {
			return Optional.of(serviceDiscovery.getServices()).map(services -> {
				ServiceCache.setServiceIds(services);
				return services;
			}).get();
		}
		catch (Exception e) {
			log.error("get service name from nacos server failed.", e);
			return failureToleranceEnabled ? ServiceCache.getServiceIds()
					: Collections.emptyList();
		}
	}

}

网站公告

今日签到

点亮在社区的每一天
去签到