Spring Cloud Nacos 服务注册发现解析
一、服务实例注册原理
1、AbstractAutoServiceRegistration
AbstractAutoServiceRegistration
是spring-cloud-commons包提供的服务注册流程模版类,不同的注册中心需要继承该类来控制相应的注册流程,及提供相应的注册实例数据
1.1、AbstractAutoServiceRegistration
源码概览
public abstract class AbstractAutoServiceRegistration<R extends Registration>
implements AutoServiceRegistration, ApplicationContextAware,
ApplicationListener<WebServerInitializedEvent> {
...
private AtomicInteger port = new AtomicInteger(0);
private final ServiceRegistry<R> serviceRegistry;
@Deprecated
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry,
AutoServiceRegistrationProperties properties) {
this.serviceRegistry = serviceRegistry;
this.properties = properties;
}
/**
* 监听web server初始化完成事件,回调方法
* WebServerInitializedEvent事件由 AbstractApplicationContext#finishRefresh() 的具体实现方法发布出来,
* 此处监听方法被回调
*/
@Override
@SuppressWarnings("deprecation")
public void onApplicationEvent(WebServerInitializedEvent event) {
bind(event);
}
@Deprecated
public void bind(WebServerInitializedEvent event) {
ApplicationContext context = event.getApplicationContext();
if (context instanceof ConfigurableWebServerApplicationContext) {
if ("management".equals(((ConfigurableWebServerApplicationContext) context)
.getServerNamespace())) {
return;
}
}
this.port.compareAndSet(0, event.getWebServer().getPort());
this.start();
}
public void start() {
if (!isEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug("Discovery Lifecycle disabled. Not starting");
}
return;
}
// only initialize if nonSecurePort is greater than 0 and it isn't already running
// because of containerPortInitializer below
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);
}
}
/**
* Register the local service with the {@link ServiceRegistry}.
*/
protected void register() {
this.serviceRegistry.register(getRegistration());
}
...
}
1.2、AbstractAutoServiceRegistration
源码说明
我们可以看到,抽象类AbstractAutoServiceRegistration
监听了WebServerInitializedEvent
事件,所以流程如下:
- spring 容器初始化完成,发布
WebServerInitializedEvent
事件 - 回调监听
WebServerInitializedEvent
事件方法AbstractAutoServiceRegistration#onApplicationEvent(WebServerInitializedEvent event)
- 调用
start()
方法执行注册操作,并在注册前后分别发布注册前置、后置事件 - 调用
register()
方法进行服务实例注册
由于
AbstractAutoServiceRegistration
是一个spring cloud 提供的抽象注册模版类,所以Nacos注册中心提供了NacosAutoServiceRegistration
的具体实现
2、NacosAutoServiceRegistration
解析
主要功能:
提供服务注册实例的基础数据(应用名称、ip 、端口、元数据等信息),以及控制注册流程
public class NacosAutoServiceRegistration
extends AbstractAutoServiceRegistration<Registration> {
private static final Logger log = LoggerFactory
.getLogger(NacosAutoServiceRegistration.class);
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 NacosRegistration getManagementRegistration() {
return null;
}
@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 void registerManagement() {
if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
return;
}
super.registerManagement();
}
@Override
protected Object getConfiguration() {
return this.registration.getNacosDiscoveryProperties();
}
@Override
protected boolean isEnabled() {
return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
}
@Override
@SuppressWarnings("deprecation")
protected String getAppName() {
String appName = registration.getNacosDiscoveryProperties().getService();
return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
}
}
3、NacosServiceRegistry 服务实例注册类
NacosServiceRegistry
通过实现spring cloud commons公用注册接口ServiceRegistry
, 来提供把服务实例注册到Nacos注册中心的能力,通过上面讲到的 AbstractAutoServiceRegistration#register()
方法来触发注册
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
private static final Logger log = LoggerFactory.getLogger(NacosServiceRegistry.class);
private final NacosDiscoveryProperties nacosDiscoveryProperties;
private final NamingService namingService;
public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.namingService = nacosDiscoveryProperties.namingServiceInstance();
}
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
// 通过服务实例基础数据拿到 serviceId
String serviceId = registration.getServiceId();
// 通过配置拿到注册分组
String group = nacosDiscoveryProperties.getGroup();
Instance instance = getNacosInstanceFromRegistration(registration);
try {
// 通过nacos提供的命名服务api namingService来注册到nacos注册中心
namingService.registerInstance(serviceId, group, instance);
log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
instance.getIp(), instance.getPort());
}
catch (Exception e) {
log.error("nacos registry, {} register failed...{},", serviceId,
registration.toString(), e);
}
}
}