SpringCloud Alibaba Nacos服务注册原理

  • Post author:
  • Post category:其他

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 事件,所以流程如下:

  1. spring 容器初始化完成,发布 WebServerInitializedEvent 事件
  2. 回调监听WebServerInitializedEvent 事件方法 AbstractAutoServiceRegistration#onApplicationEvent(WebServerInitializedEvent event)
  3. 调用start() 方法执行注册操作,并在注册前后分别发布注册前置、后置事件
  4. 调用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);
		}
	}

}

版权声明:本文为minemine0418原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。