// 核心作用
// 导入具体的DiscoveryClient实现,例如: NacosDiscoveryClient
// DiscoveryClient: 可以获取所有实例信息,实例ID列表
@EnableDiscoveryClient
public class App {
}
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
// 如果为true, ServiceRegistry将自动注册本地服务器
boolean autoRegister() default true;
}
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector extends SpringFactoryImportSelector<EnableDiscoveryClient> {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
// 从Spring.factories文件中加载EnableDiscoveryClient类型的数据导入
String[] imports = super.selectImports(metadata);
// 获取EnableDiscoveryClient注解信息
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
// 获取自动注册标识
boolean autoRegister = attributes.getBoolean("autoRegister");
// 如果是自动注册
if (autoRegister) {
// 导入工厂类以及自动注册的配置类
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
/**
* {@link AutoServiceRegistrationConfiguration}
*/
importsList.add("org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
} else {
// 如果不是自动注册
Environment env = getEnvironment();
if (env instanceof ConfigurableEnvironment configEnv) {
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
// 设置自动注册的属性值为false
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
// 将该属性添加到上下文环境对象中
MapPropertySource propertySource = new MapPropertySource("springCloudDiscoveryClient", map);
configEnv.getPropertySources().addLast(propertySource);
}
}
return imports;
}
// 开启标识: spring.cloud.discovery.enabled,默认为true
@Override
protected boolean isEnabled() {
return getEnvironment().getProperty("spring.cloud.discovery.enabled", Boolean.class, Boolean.TRUE);
}
// 存在默认的工厂类,能处理该注解,说明存在默认处理DiscoveryClient的类
// 默认为: SimpleDiscoveryClient,如果导入了其他的DiscoveryClient依赖,那么就会存在对应的DiscoveryClient实现
// 例如: Nacos -> NacosDiscoveryClient
@Override
protected boolean hasDefaultFactory() {
return true;
}
}
public abstract class SpringFactoryImportSelector<T> implements DeferredImportSelector, BeanClassLoaderAware, EnvironmentAware {
// Bean的类加载器
private ClassLoader beanClassLoader;
// 处理的注解类型(@EnableDiscoveryClient)
private Class<T> annotationClass;
// 上下文环境对象
private Environment environment;
protected SpringFactoryImportSelector() {
// 类中的泛型注解信息(@EnableDiscoveryClient)
this.annotationClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(this.getClass(), SpringFactoryImportSelector.class);
}
@Override
public String[] selectImports(AnnotationMetadata metadata) {
// 如果没有开启,不处理
if (!this.isEnabled()) {
return new String[0];
}
// 获取注解的属性信息
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(this.annotationClass.getName(), true));
/**
* 例如: 类似与这种效果,但是也可以通过其他方式,核心就是导入DiscoveryClient的实现
* <pre>
* org.springframework.cloud.client.discovery.EnableDiscoveryClient=\
* org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration,\
* org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
* org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
* org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration,\
* com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
* org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryClientConfiguration,\
*</pre>
*/
// 从Spring.factories文件中加载EnableDiscoveryClient为Key的自动配置类
List<String> factories = new ArrayList<>(new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(this.annotationClass, this.beanClassLoader)));
// 如果为空并且不包含默认的处理DiscoveryClient的工厂类,抛出异常,意思是: 找到注解找不到DiscoveryClient实现
if (factories.isEmpty() && !hasDefaultFactory()) {
throw new IllegalStateException("Annotation @" + getSimpleName() + " found, but there are no implementations. Did you forget to include a starter?");
}
// 应该只有一个DiscoveryClient,但可能不止一个处理DiscoveryClient的工厂
if (factories.size() > 1) {
this.log.warn("More than one implementation " + "of @" + getSimpleName() + " (now relying on @Conditionals to pick one): " + factories);
}
// 导入从Spring.factories文件中加载EnableDiscoveryClient类型的数据
return factories.toArray(new String[factories.size()]);
}
// 给子类重写
// 默认不存在工厂类,无法处理该注解
protected boolean hasDefaultFactory() {
return false;
}
protected abstract boolean isEnabled();
}
@Configuration(proxyBeanMethods = false)
// 导入自动注册的配置类
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
// spring.cloud.service-registry.auto-registration.enabled开启则导入AutoServiceRegistrationProperties配置类,默认为true
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}
// 导入了依赖,会自动注册DiscoveryClient的实现,下面是各种实现之一
// org.springframework.cloud.client.discovery.EnableDiscoveryClient=\
// org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration,\
// org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration,\
// org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
// org.springframework.cloud.consul.discovery.ConsulDiscoveryClientConfiguration,\
// com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
// org.springframework.cloud.zookeeper.discovery.ZookeeperDiscoveryClientConfiguration,\
// 解析DiscoveryClient配置类,以Nacos为例
@Configuration(proxyBeanMethods = false)
// 对应的spring.cloud.discovery.enabled属性配置为true,才会加载,默认值都为true
@ConditionalOnDiscoveryEnabled
// 对应的spring.cloud.discovery.blocking.enabled属性配置为true,才会加载,默认值都为true
@ConditionalOnBlockingDiscoveryEnabled
// 对应的spring.cloud.nacos.discovery.enabled属性配置为true,才会加载,默认值都为true
@ConditionalOnNacosDiscoveryEnabled
// SimpleDiscoveryClientAutoConfiguration和CommonsClientAutoConfiguration需要在当前类加载之前加载
// 因为这两个配置是默认的提供的实现配置
@AutoConfigureBefore({SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class})
// NacosDiscoveryAutoConfiguration需要在当前类加载之后再进行加载
@AutoConfigureAfter(NacosDiscoveryAutoConfiguration.class)
public class NacosDiscoveryClientConfiguration {
// 导入Nacos的服务发现客户端实现
@Bean
public DiscoveryClient nacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
return new NacosDiscoveryClient(nacosServiceDiscovery);
}
// 导入Nacos的监控类
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.nacos.discovery.watch.enabled", matchIfMissing = false)
public NacosWatch nacosWatch(NacosServiceManager nacosServiceManager, NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosWatch(nacosServiceManager, nacosDiscoveryProperties);
}
// 网关心跳检测的事件发布器
// 使用定时线程池,在固定的时间间隔,发送心跳包
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.gateway.discovery.locator.enabled", matchIfMissing = false)
public GatewayLocatorHeartBeatPublisher gatewayLocatorHeartBeatPublisher(NacosDiscoveryProperties nacosDiscoveryProperties) {
return new GatewayLocatorHeartBeatPublisher(nacosDiscoveryProperties);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
@ConditionalOnNacosDiscoveryEnabled
public class NacosServiceAutoConfiguration {
@Bean
public NacosServiceManager nacosServiceManager() {
return new NacosServiceManager();
}
}
@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);
}
}
// Nacos服务发现
public class NacosServiceDiscovery {
// Nacos服务发现配置属性
private NacosDiscoveryProperties discoveryProperties;
// Nacos服务管理器
private NacosServiceManager nacosServiceManager;
public NacosServiceDiscovery(NacosDiscoveryProperties discoveryProperties, NacosServiceManager nacosServiceManager) {
this.discoveryProperties = discoveryProperties;
this.nacosServiceManager = nacosServiceManager;
}
// 根据实例ID返回所有的实例对象
public List<ServiceInstance> getInstances(String serviceId) throws NacosException {
String group = discoveryProperties.getGroup();
List<Instance> instances = namingService().selectInstances(serviceId, group, true);
// 将Nacos的实例信息转换为SpringCloud规定的实例信息
return this.hostToServiceInstanceList(instances, serviceId);
}
// 返回所有的实例名称
public List<String> getServices() throws NacosException {
String group = discoveryProperties.getGroup();
ListView<String> services = namingService().getServicesOfServer(1, Integer.MAX_VALUE, group);
return services.getData();
}
// 将Nacos的实例信息转换为SpringCloud规定的实例信息
public static List<ServiceInstance> hostToServiceInstanceList(List<Instance> instances, String serviceId) {
List<ServiceInstance> result = new ArrayList<>(instances.size());
// 遍历Nacos的实例信息
for (Instance instance : instances) {
// 将Nacos的实例信息转换为SpringCloud规定的实例信息
ServiceInstance serviceInstance = this.hostToServiceInstance(instance, serviceId);
if (serviceInstance != null) {
result.add(serviceInstance);
}
}
return result;
}
// 将Nacos的实例信息转换为SpringCloud规定的实例信息
public static ServiceInstance hostToServiceInstance(Instance instance, String serviceId) {
if (instance == null || !instance.isEnabled() || !instance.isHealthy()) {
return null;
}
NacosServiceInstance nacosServiceInstance = new NacosServiceInstance();
nacosServiceInstance.setHost(instance.getIp());
nacosServiceInstance.setPort(instance.getPort());
nacosServiceInstance.setServiceId(serviceId);
nacosServiceInstance.setInstanceId(instance.getInstanceId());
Map<String, String> metadata = new HashMap<>();
metadata.put("nacos.instanceId", instance.getInstanceId());
metadata.put("nacos.weight", instance.getWeight() + "");
metadata.put("nacos.healthy", instance.isHealthy() + "");
metadata.put("nacos.cluster", instance.getClusterName() + "");
if (instance.getMetadata() != null) {
metadata.putAll(instance.getMetadata());
}
metadata.put("nacos.ephemeral", String.valueOf(instance.isEphemeral()));
nacosServiceInstance.setMetadata(metadata);
if (metadata.containsKey("secure")) {
boolean secure = Boolean.parseBoolean(metadata.get("secure"));
nacosServiceInstance.setSecure(secure);
}
return nacosServiceInstance;
}
// 获取Nacos的名称服务对象,该对象负责管理所有的服务实例,包括注册,取消注册
private NamingService namingService() {
return nacosServiceManager.getNamingService();
}
}
// Nacos的服务发现客户端
public class NacosDiscoveryClient implements DiscoveryClient {
public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";
// Nacos的服务发现
private NacosServiceDiscovery serviceDiscovery;
// 是否启用容错机制,默认为false
@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 {
// 根据服务ID获取实例
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);
}
}
// 获取服务名称ID
@Override
public List<String> getServices() {
try {
// 从服务发现中获取所有的实例ID,并缓存起来
return Optional.of(serviceDiscovery.getServices()).map(services -> {
ServiceCache.setServiceIds(services);
return services;
}).get();
} catch (Exception e) {
// 获取的过程发生异常
// 如果开启了容器机制,返回缓存中的实例ID,否则返回空实例ID
log.error("get service name from nacos server failed.", e);
return failureToleranceEnabled ? ServiceCache.getServiceIds() : Collections.emptyList();
}
}
}
SpringCloud中@EnableDiscoveryClient的源码解析
于 2024-05-27 10:45:26 首次发布