目录
加载自动装配类
spring boot 在启动后扫描【spring-cloud-alibaba-nacos-discovery】jar包 下的spring.factory文件。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.alibaba.nacos.NacosDiscoveryAutoConfiguration,\
org.springframework.cloud.alibaba.nacos.ribbon.RibbonNacosAutoConfiguration,\
org.springframework.cloud.alibaba.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,\
org.springframework.cloud.alibaba.nacos.discovery.NacosDiscoveryClientAutoConfiguration
其中负责服务注册的自动化配置类是 org.springframework.cloud.alibaba.nacos.NacosDiscoveryAutoConfiguration
该类会创建NacosServiceRegistry NacosRegistration NacosAutoServiceRegistration 3个Bean
@Bean
public NacosServiceRegistry nacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties);
}
@Bean
@ConditionalOnBean({AutoServiceRegistrationProperties.class})
public NacosRegistration nacosRegistration(NacosDiscoveryProperties nacosDiscoveryProperties, ApplicationContext context) {
return new NacosRegistration(nacosDiscoveryProperties, context);
}
@Bean
@ConditionalOnBean({AutoServiceRegistrationProperties.class})
public NacosAutoServiceRegistration nacosAutoServiceRegistration(NacosServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);
}
NacosRegistration:封装服务注册的基本信息 包括服务的serviceId 服务的Ip 和 port 、Cluster(所属集群) 、Weight(服务的权重)、isSecure、uri(http[https]://ip:port/)、metaData(服务扩展数据)、namingService 这些属性基本上都是通过属性配置文件配置的
NacosAutoServiceRegistration : 服务启动后该类监听web server 初始化事件触发 服务注册流程
NacosServiceRegistry 负责服务的注册和下线功能
服务注册触发时机
NacosAutoServiceRegistration 的父类AbstractAutoServiceRegistration监听了WebServer 初始化事件,当监听到web server 初始化事件时执行 bind(WebServerInitializedEvent event) 方法
服务启动事件触发方法:bind(WebServerInitializedEvent event):
//服务器在初始化时唤醒该方法
public void bind(WebServerInitializedEvent event) {
ApplicationContext context = event.getApplicationContext();
...
this.port.compareAndSet(0, event.getWebServer().getPort());
this.start();
}
public void start() {
// 如果服务如果已注册过则跳过
if (!this.running.get()) {
//发布注册前事件
this.context.publishEvent(
new InstancePreRegisteredEvent(this, getRegistration()));
// 服务注册入口
register();
if (shouldRegisterManagement()) {
registerManagement();
}
//发布注册后事件
this.context.publishEvent(
new InstanceRegisteredEvent<>(this, getConfiguration()));
//设置服务已注册状态
this.running.compareAndSet(false, true);
}
}
// 调用NacosServiceRegistry 注册
protected void register() {
this.serviceRegistry.register(getRegistration());
}
通过代码可以看出服务注册是调用的serviceRegistry.registry方法.
这里的serviceRegistry 就是我们上面自动装配类里面的NacosServiceRegistry类
服务注册核心流程
核心代码讲解
//服务启动后该类监听web server 初始化事件触发 服务注册流程
public class NacosAutoServiceRegistration
extends AbstractAutoServiceRegistration<Registration> {
//包装了服务注册基本信息[注册信息]
private NacosRegistration registration;
public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration;
}
@Deprecated
public void setPort(int port) {
getPort().set(port);
}
//如果属性文件配置的端口不合法重新设置端口
@Override
protected NacosRegistration getRegistration() {
if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
this.registration.setPort(this.getPort().get());
}
Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
return this.registration;
}
...
//调用父方法实现注册
@Override
protected void register() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
log.debug("Registration disabled.");
return;
}
if (this.registration.getPort() < 0) {
this.registration.setPort(getPort().get());
}
super.register();
}
...
// 用户在配置文件中配置的属性
@Override
protected Object getConfiguration() {
return this.registration.getNacosDiscoveryProperties();
}
//是否可以启用服务注册[纯消费者可以设置该属性为false]
@Override
protected boolean isEnabled() {
return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
}
//首先从[spring.cloud.nacos.discovery.service]获取appName, 如果没有获取到则从
// [spring.application.name]属性获取
@Override
@SuppressWarnings("deprecation")
protected String getAppName() {
String appName = registration.getNacosDiscoveryProperties().getService();
return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
}
}
//实现ServiceRegistry接口的服务注册 spring正是通过该接口为nacos的注册服务提供了可能
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
...
private final NacosDiscoveryProperties nacosDiscoveryProperties;
private final NamingService namingService;
...
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
String serviceId = registration.getServiceId();
//创建要注册的实例
Instance instance = new Instance();
instance.setIp(registration.getHost());
instance.setPort(registration.getPort());
instance.setWeight(nacosDiscoveryProperties.getWeight());
instance.setClusterName(nacosDiscoveryProperties.getClusterName());
instance.setMetadata(registration.getMetadata());
...
namingService.registerInstance(serviceId, instance);
log.info("nacos registry, {} {}:{} register finished", serviceId,
instance.getIp(), instance.getPort());
...
}
//服务下线功能
@Override
public void deregister(Registration registration) {
...
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
String serviceId = registration.getServiceId();
...
namingService.deregisterInstance(serviceId, registration.getHost(),
registration.getPort(), nacosDiscoveryProperties.getClusterName());
...
}
@Override
public void close() {
}
@Override
public void setStatus(Registration registration, String status) {
// nacos doesn't support set status of a particular registration.
}
@Override
public <T> T getStatus(Registration registration) {
// nacos doesn't support query status of a particular registration.
return null;
}
}
上面的serverId 就是属性文件配置的service 或者 appName 属性。
通过代码可以看出首先通过 Registration和 nacosDiscoveryProperties[配置文件相关属性] 构建一个Instance 对象 然后调用下一章要详细讲解的 NacosNamingService 统一发起注册和下线功能
注意: NacosRegistration 负责包装 配置属性文件里面的属性 。比spring cloud的 Registration 接口提供了更多的属性比如 registerWeight、Cluster、isRegisterEnabled等。因此你可以理解了 为什么 weight 性和 clusterName 要从 nacosDiscoveryProperties 去获而不是通过 registration 去获取
instance.setWeight(nacosDiscoveryProperties.getWeight());
instance.setClusterName(nacosDiscoveryProperties.getClusterName());
Instance: 注册的实例信息 字段如下类图:
- Instance: 有几个重要的属性分别是: ip、端口、权重(不能小于1)、集群名、扩展信息
- nacos: 的数据模型从上到下 namespace -> service -> group -> cluster -> instance
- namespace : 待注册实例所属的空间一般可以表示不同的环境 默认是PUBLIC
- service: 注册服务名
- group: 待注册实例所属分组 默认是:DEFAULT_GROUP
- cluster: 待注册实例所属集群 默认是:DEFAULT
总结
Nacos 之所以可以作为独立的第三方注册中心集成到spring cloud 里面核心的原因是spring cloud提供下面3个接口或抽象类作为扩展点
class AbstractAutoServiceRegistration
Interface ServiceRegistry
Interface Registration
所以nacos的第一个启动的自动装配类【NacosDiscoveryAutoConfiguration】就是 创建基于上面3个接口的实现类。
后面的所有注册流程就完全进入到了nacos自己的实现中。