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

DiscoveryClient

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

java 复制代码
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 自动配置类,基于配置文件属性创建一个简单的服务发现客户端。

java 复制代码
/**
 * 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 实现,使用属性文件作为服务实例的来源,提供获取服务实例和服务列表的功能。

java 复制代码
/**
 * 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 合并成一个客户端。

java 复制代码
/**
 * 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 组合在一起的客户端,它依次查询各个客户端获取服务实例,确保高可用性和灵活性。

java 复制代码
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 服务发现启用时创建所需的 NacosDiscoveryProperties 和 NacosServiceDiscovery Bean,并确保在没有其他相关 Bean 的情况下提供默认配置。

java 复制代码
@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 服务发现客户端及其相关功能,如 DiscoveryClient 和 NacosWatch。

java 复制代码
@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 服务发现交互,提供获取服务实例和服务列表的功能,同时支持故障容错。

java 复制代码
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();
		}
	}

}
相关推荐
青春不朽51214 分钟前
Python 里 a is b 有时 True 有时 False?小整数缓存和常量折叠的底层真相
python·spring·缓存
苏渡苇32 分钟前
Spring Insight:跨服务调用链路是怎么串起来的?
spring boot·后端·spring·系统监控·apm
夕除2 小时前
redis--主从还是集群,内存
java·spring·mybatis
霸道流氓气质3 小时前
AI 简历制作平台:结构化输出解析、多模板渲染与 PDF 导出的 Vue3 + Spring AI 全栈实战
人工智能·spring·pdf
打工仔折腾 AI3 小时前
Spring AI + Qwen 周报生成实战:从原始日志到人工确认卡
人工智能·后端·python·spring·elasticsearch·ai agent 实战
开开心心就好3 小时前
手机电池健康怎么查?看容量温度循环次数
spring·智能手机·ffmpeg·计算机外设·电脑·maven·音视频
云和数据.ChenGuang3 小时前
Spring AI 对接 LangGraph:构建企业级智能体工作流实战
java·人工智能·spring boot·后端·spring
云和数据.ChenGuang3 小时前
Spring AI 入门实战:构建你的第一个 AI 应用
java·人工智能·深度学习·spring·机器学习·语言模型
从零到一未来可期4 小时前
第8集:MCP协议:一个协议让AI接入所有企业系统
spring·spring cloud
木棉软糖4 小时前
JDBC 读 ResultSet 读到一半,报 stream closed
java·mysql·spring