Spring Cloud microservice registration underlying principle and encapsulation

We all know that nacos is the middleware used as the registration center and configuration center in microservices. This article will explore how Spring Cloud registers services into the registration center, and how nacos implements its own code logic in the above specifications. . This article uses nacos as an example.

process

We all know that Spring provides many extension points, including the BeanFactoryPostProcessor in the BeanFactory post-processor, the BeanPostProcessor after a Bean is created, and so on.

  • So how is service registration implemented?

To solve this problem, let's first look at the core code in Spring.

AbstractApplicationContext#refresh()

@Override
public void refresh() throws BeansException, IllegalStateException {
    
    
	synchronized (this.startupShutdownMonitor) {
    
    
		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
    
    
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			// nacos客户端注册处
			finishRefresh();
		} catch (BeansException ex) {
    
    
			if (logger.isWarnEnabled()) {
    
    
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
    
    
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

At the end of the entire container refresh phase, nacos will register the service. So let's see how to register the service here.

@Override
public void publishEvent(ApplicationEvent event) {
    
    
	publishEvent(event, null);
}

First, an event ServletWebServerInitializedEvent is released . This event will be monitored by all listeners and then triggered.

Insert image description here

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    
    
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	Executor executor = getTaskExecutor();
	for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
    
    
		if (executor != null) {
    
    
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
    
    
			invokeListener(listener, event);
		}
	}
}
  • Obtain all listeners and call events one by one, a typical observer design pattern.

Finally, we found that Nacos registered a listener NacosAutoServiceRegistration in the container.

This class implements ApplicationListener , so it will definitely call back the onApplicationEvent method when it listens to the ServletWebServerInitializedEvent event. But he did not override the onApplicationEvent method, so he called the onApplicationEvent method of the parent class.
We can look at onApplicationEvent in AbstractAutoServiceRegistration.

/**
 * Register the local service with the {@link ServiceRegistry}.
 */
protected void register() {
    
    
	this.serviceRegistry.register(getRegistration());
}

Insert image description here

Finally, after port binding, determining whether to enable service registration, etc., register with the registration center.

// NacosAutoServiceRegistration#register
@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();
}

// super.register调用的该处代码AbstractAutoServiceRegistration#register
protected void register() {
    
    
	this.serviceRegistry.register(getRegistration());
}

The above are actually the specifications that Spring Cloud has helped us encapsulate. In the end, we need to call
this.serviceRegistry.register(getRegistration());
to perform the corresponding registration operation. For example, nacos and erueka just call the corresponding implementation class.

2. Encapsulation

We know from the above that nacos essentially places a listener in the container and performs registration operations by listening to the web service initialization event ServletWebServerInitializedEvent .
So let’s take a look at what is put into the container and how it is put into the container.

1. Automatic assembly

We all know that Spring boot automatically assembles by configuring the spring.factories file in the jar package. Then let's see if nacos also puts its own implementation class in this way.

Check the META-INF/spring.factories file under nacos discovery
and find the configuration class for automatically registering the client.

Insert image description here

Let's take a look at this configuration class and what classes are introduced into the container. Sure enough, we discovered that the previous section mentioned the automatic registration component implementation class.

/*
 * Copyright 2013-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.cloud.nacos.registry;

// 省略
import *

/**
 * @author xiaojing
 * @author <a href="mailto:[email protected]">Mercy</a>
 */
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
		matchIfMissing = true)
@AutoConfigureAfter({
    
     AutoServiceRegistrationConfiguration.class,
		AutoServiceRegistrationAutoConfiguration.class,
		NacosDiscoveryAutoConfiguration.class })
public class NacosServiceRegistryAutoConfiguration {
    
    

	@Bean
	public NacosServiceRegistry nacosServiceRegistry(
			NacosDiscoveryProperties nacosDiscoveryProperties) {
    
    
		return new NacosServiceRegistry(nacosDiscoveryProperties);
	}

	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	public NacosRegistration nacosRegistration(
			ObjectProvider<List<NacosRegistrationCustomizer>> registrationCustomizers,
			NacosDiscoveryProperties nacosDiscoveryProperties,
			ApplicationContext context) {
    
    
		return new NacosRegistration(registrationCustomizers.getIfAvailable(),
				nacosDiscoveryProperties, context);
	}
	
	/**
	*	注册实例的关键类,通过使用上面NacosServiceRegistry进行NacosRegistration注册
	*/
	@Bean
	@ConditionalOnBean(AutoServiceRegistrationProperties.class)
	public NacosAutoServiceRegistration nacosAutoServiceRegistration(
			NacosServiceRegistry registry,
			AutoServiceRegistrationProperties autoServiceRegistrationProperties,
			NacosRegistration registration) {
    
    
		return new NacosAutoServiceRegistration(registry,
				autoServiceRegistrationProperties, registration);
	}

}

When creating NacosAutoServiceRegistration, NacosServiceRegistry and NacosRegistration were passed in.
Makes it call to register when registering.

protected void register() {
    
    
	this.serviceRegistry.register(getRegistration());
}

3. Summary

The principle of Spring Cloud service registration is to listen through the listener after the Spring container is initialized, and then call the corresponding listener to register the service. Nacos implements a full set of registration components, which can be realized by simply introducing and configuring the address, and automating the service registration function.

Guess you like

Origin blog.csdn.net/qq_40922616/article/details/124039481
Recommended