Spring Boot
版本:2.2.9.RELEASE
Spring Cloud
版本:Hoxton.SR6
Spring Cloud Alibaba
版本:2.2.1.RELEASE
Nacos
版本:1.3.1
1 @EnableDiscoveryClient
如果需要启用服务注册功能,需要在启动类上面添加@EnableDiscoveryClient
注解。
查看@EnableDiscoveryClient
的源码:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
/**
* 默认返回值为true。
* 如果返回值为true,ServiceRegistry将会自动将本服务注册到服务注册中心。
*/
boolean autoRegister() default true;
}
@EnableDiscoveryClient
注解的源码中有一个方法autoRegister()
,默认返回true
,表示希望自动注册服务。
@EnableDiscoveryClient
还通过@Import
注解引入了EnableDiscoveryClientImportSelector
类,查看源码:
@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector
extends SpringFactoryImportSelector<EnableDiscoveryClient> {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
// 获取@EnableDiscoveryClient注解的属性autoRegister的值
boolean autoRegister = attributes.getBoolean("autoRegister");
// 如果autoRegister == true,加载AutoServiceRegistrationConfiguration配置类
if (autoRegister) {
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
importsList.add(
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
}
// 如果autoRegister == false,设置spring.cloud.service-registry.auto-registration.enabled=false,关闭服务自动注册功能
else {
Environment env = getEnvironment();
if (ConfigurableEnvironment.class.isInstance(env)) {
ConfigurableEnvironment configEnv = (ConfigurableEnvironment) env;
LinkedHashMap<String, Object> map = new LinkedHashMap<>();
map.put("spring.cloud.service-registry.auto-registration.enabled", false);
MapPropertySource propertySource = new MapPropertySource(
"springCloudDiscoveryClient", map);
configEnv.getPropertySources().addLast(propertySource);
}
}
return imports;
}
@Override
protected boolean isEnabled() {
return getEnvironment().getProperty("spring.cloud.discovery.enabled",
Boolean.class, Boolean.TRUE);
}
@Override
protected boolean hasDefaultFactory() {
return true;
}
}
主要关注selectImports(...)
这个方法。首先获取@EnableDiscoveryClient
注解的属性autoRegister
的值。
-
如果
autoRegister == true
,加载org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration
配置类的配置。 -
如果
autoRegister == false
,设置spring.cloud.service-registry.auto-registration.enabled=false
,关闭自动服务注册功能。因为服务自动注册相关的类在注册到Spring
容器的时候都有一个条件@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
。
查看AutoServiceRegistrationConfiguration
配置类源码:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}
可以看到,这个类加载了AutoServiceRegistrationProperties
这个属性类,这个类里面维护了所有spring.cloud.service-registry.auto-registration
开头的属性的配置值。
@ConfigurationProperties("spring.cloud.service-registry.auto-registration")
public class AutoServiceRegistrationProperties {
/** Whether service auto-registration is enabled. Defaults to true. */
private boolean enabled = true;
/** Whether to register the management as a service. Defaults to true. */
private boolean registerManagement = true;
/**
* Whether startup fails if there is no AutoServiceRegistration. Defaults to false.
*/
private boolean failFast = false;
...
}
可以看到,spring.cloud.service-registry.auto-registration.enabled
默认值就是true
。也就是说,如果没有使用@EnableDiscoveryClient
注解,服务也会被自动注册,因为@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
这个条件默认情况下就是满足的。
但是如果不想自动注册服务,可以通过使用@EnableDiscoveryClient(autoRegister = false)
,或者直接在配置文件中设置spring.cloud.service-registry.auto-registration.enabled=false
。
2 Spring Cloud定义的服务发现的统一规范
拥有服务注册的中间件有很多,比如Euerka
、Consul
、ZooKeeper
、Nacos
等,想要接入Spring Cloud
就必须遵守一套统一的规范,Spring Cloud
将这套规范定义在了Spring Cloud Common
中:
spring-cloud-commons
-- org.springframework.cloud
-- client
-- discovery
-- loadbalancer
-- serviceregistry
discovery
包下面定义了服务发现的规范,loadbalancer
包下面定义了负载均衡的规范,serviceregistry
包下面定义了服务注册的规范。
org.springframework.cloud.client.serviceregistry
包下面有三个接口,这是服务注册的核心接口:
AutoServiceRegistration
接口Registration
接口ServiceRegistry
接口
2.1 AutoServiceRegistration接口
AutoServiceRegistration
用于服务自动注册。自动注册的意思就是,服务启动后自动把服务信息注册到注册中心。
public interface AutoServiceRegistration {
}
这个接口没有定义方法,它的存在就是要规范实现必须要有自动注册。
Spring Cloud
中有一个抽象类AbstractAutoServiceRegistration
实现了这个接口。
2.2 Registration接口
Registration
存储服务信息,用于规范将什么信息注册到注册中心。
public interface Registration extends ServiceInstance {
}
Registration
继承ServiceInstance
接口,ServiceInstance
接口定义了一个服务实例应该具有哪些服务信息,源码如下:
public interface ServiceInstance {
// 返回服务实例唯一ID
default String getInstanceId() {
return null;
}
// 返回服务ID,服务名称
String getServiceId();
// 返回服务实例所在的主机的host值
String getHost();
// 返回服务实例的port
int getPort();
// 返回服务的实例port是否启用了https协议
boolean isSecure();
// 返回服务的URI地址
URI getUri();
// 返回服务实力的元数据
Map<String, String> getMetadata();
// 返回服务实例的scheme
default String getScheme() {
return null;
}
}
2.3 ServiceRegistry接口
ServiceRegistry
是服务注册接口,用来向注册中心注册服务。
public interface ServiceRegistry<R extends Registration> {
// 注册服务,registration保存了服务的信息
void register(R registration);
// 反注册,也就是从注册中心移除注册的服务信息
void deregister(R registration);
// 关闭ServiceRegistry,这是一个生命周期函数
void close();
/**
* 设置服务的状态,status的值取决于具体的实现。
* 查看org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
*/
void setStatus(R registration, String status);
/**
* 获取服务状态值。
* 查看org.springframework.cloud.client.serviceregistry.endpoint.ServiceRegistryEndpoint
*/
<T> T getStatus(R registration);
}
3 Nacos服务注册的实现
Nacos
服务注册模块按照Spring Cloud
的规范,实现了AutoServiceRegistration
、Registration
、ServiceRegistry
三个接口,具体的实现了分别是:
NacosAutoServiceRegistration
类NacosRegistration
类NacosServiceRegistry
类
这三个类位于spring-cloud-starter-alibaba-nacos-discovery
包中的com.alibaba.cloud.nacos.registry
包路径下。
3.1 NacosRegistration
首先看看NacosRegistration
,这个类管理了Nacos
服务的基本信息,如服务名、服务地址和端口等信息。
它实现了Spring Cloud
定义的规范接口Registration
,同时也实现了ServiceInstance
接口。
不过实际上Nacos
服务的基本信息都是由NacosDiscoveryProperties
这个类来保存的,NacosRegistration
只是对NacosDiscoveryProperties
进行了封装而已。
public class NacosRegistration implements Registration, ServiceInstance {
/**
* management port
*/
public static final String MANAGEMENT_PORT = "management.port";
/**
* management context-path.
*/
public static final String MANAGEMENT_CONTEXT_PATH = "management.context-path";
/**
* management address.
*/
public static final String MANAGEMENT_ADDRESS = "management.address";
/**
* management endpoints web base path.
*/
public static final String MANAGEMENT_ENDPOINT_BASE_PATH = "management.endpoints.web.base-path";
// 配置文件中spring.cloud.nacos.discovery开头的配置的映射类
private NacosDiscoveryProperties nacosDiscoveryProperties;
// 应用上下文
private ApplicationContext context;
// 构造函数注入
public NacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties,
ApplicationContext context) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.context = context;
}
// 当构造函数执行之后执行的初始化
@PostConstruct
public void init() {
Map<String, String> metadata = nacosDiscoveryProperties.getMetadata();
Environment env = context.getEnvironment();
String endpointBasePath = env.getProperty(MANAGEMENT_ENDPOINT_BASE_PATH);
if