Nacos服务注册的实现
Nacos的服务注册主要是实现了NacosAutoServiceRegistration类、NacosRegistration类与NacosServiceRegistry类
NacosRegistration
首先看看NacosRegistration,这个类管理了Nacos服务的基本信息,比如服务名、服务地址等等。实际上Nacos服务的基本信息都是由NacosDiscoveryProperties这个类来保存的,由NacosRegistration进行封装信息。
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 (!StringUtils.isEmpty(endpointBasePath)) {
metadata.put(MANAGEMENT_ENDPOINT_BASE_PATH, endpointBasePath);
}
Integer managementPort = ManagementServerPortUtils.getPort(context);
if (null != managementPort) {
metadata.put(MANAGEMENT_PORT, managementPort.toString());
String contextPath = env
.getProperty("management.server.servlet.context-path");
String address = env.getProperty("management.server.address");
if (!StringUtils.isEmpty(contextPath)) {
metadata.put(MANAGEMENT_CONTEXT_PATH, contextPath);
}
if (!StringUtils.isEmpty(address)) {
metadata.put(MANAGEMENT_ADDRESS, address);
}
}
if (null != nacosDiscoveryProperties.getHeartBeatInterval()) {
metadata.put(PreservedMetadataKeys.HEART_BEAT_INTERVAL,
nacosDiscoveryProperties.getHeartBeatInterval().toString());
}
if (null != nacosDiscoveryProperties.getHeartBeatTimeout()) {
metadata.put(PreservedMetadataKeys.HEART_BEAT_TIMEOUT,
nacosDiscoveryProperties.getHeartBeatTimeout().toString());
}
if (null != nacosDiscoveryProperties.getIpDeleteTimeout()) {
metadata.put(PreservedMetadataKeys.IP_DELETE_TIMEOUT,
nacosDiscoveryProperties.getIpDeleteTimeout().toString());
}
}
// getter、setter
...
}
NacosServiceRegistry
NacosServiceRegistry实现了ServiceRegistry接口,它主要是把服务实例注册到Nacos的注册中心。然后重点关注register与deregister,这两个方法主要是实现了服务的注册和反注册。
最后面Nacos都是通过NamingService来完成这两个功能的,NamingService在启动的时候封装了Nacos注册中心的信息,并且也把服务注册和反注册相关的http请求也封装了。
@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();
// 分组
String group = nacosDiscoveryProperties.getGroup();
// 创建服务实例对象
Instance instance = getNacosInstanceFromRegistration(registration);
try {
// 通过namingService将服务实例注册到注册中心
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);
// rethrow a RuntimeException if the registration is failed.
// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
rethrowRuntimeException(e);
}
}
@Override
public void deregister(Registration registration) {
log.info("De-registering from Nacos Server now...");
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No dom to de-register for nacos client...");
return;
}
// 获取namingService
NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
// 服务名
String serviceId = registration.getServiceId();
// 分组
String group = nacosDiscoveryProperties.getGroup();
try {
// 通过namingService反注册当前服务实例
namingService.deregisterInstance(serviceId, group, registration.getHost(),
registration.getPort(), nacosDiscoveryProperties.getClusterName());
}
catch (Exception e) {
log.error("ERR_NACOS_DEREGISTER, de-register failed...{},",
registration.toString(), e);
}
log.info("De-registration finished.");
}
NacosAutoServiceRegistration
NacosAutoServiceRegistration这个类实现了服务自动注册到Nacos注册中心的功能
public abstract class AbstractAutoServiceRegistration<R extends Registration>
implements AutoServiceRegistration, ApplicationContextAware,
ApplicationListener<WebServerInitializedEvent> {
...
}
可以看到,实现了ApplicationListener,说明可以被事件回调。当容器启动之后,应用上下文被刷新并且WebServer准备就绪之后,会触发WebServerInitializedEvent事件,那么抽象类中的onApplicationEvent(WebServerInitializedEvent event)方法就会被调用。
@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();
String group = nacosDiscoveryProperties.getGroup();
Instance instance = getNacosInstanceFromRegistration(registration);
try {
// 最后由namingService实现服务注册
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);
// rethrow a RuntimeException if the registration is failed.
// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
rethrowRuntimeException(e);
}
}
到最后面,实际调用的是serviceRegistry的register方法,而serviceRegistry是在构造NacosAutoServiceRegistration的时候传入的NacosServiceRegistry。所以实际上是调用的NacosServiceRegistry的register方法。
其他配置类NacosServiceRegistryAutoConfiguration
这个NacosServiceRegistryAutoConfiguration类是为了使用Spring Boot自动装配功能的一个自动配置类
@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(
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);
}
}
第一步这个自动装配类首先使用了@EnableConfigurationProperties注解,这个注解能够使用@ConfigurationProperties注解但是的话却没有用@Component等注解实例化为bean的类生效。因为NacosDiscoveryProperties类使用了@ConfigurationProperties("spring.cloud.nacos.discovery")注解,但是没有@Component注解,Spring容器不会实例化这个类,所以需要通过@EnableConfigurationProperties注解让NacosDiscoveryProperties被实例化并注入到容器中。这样就能获取到配置文件中配置的Nacos相关的配置值。
第二步然后使用了@ConditionalOnNacosDiscoveryEnabled注解。这个注解的意思是spring.cloud.nacos.discovery.enabled=true的时候(默认是true),NacosServiceRegistryAutoConfiguration这个配置类才会生效。
第三步然后使用了@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)注解。这个注解的意思是当spring.cloud.service-registry.auto-registration.enabled=true的时候,NacosServiceRegistryAutoConfiguration这个配置类才会生效。默认情况下就是true。
第四步就使用注解,这个注解的意思是要在AutoServiceRegistrationConfiguration、AutoServiceRegistrationAutoConfiguration、NacosDiscoveryAutoConfiguration配置类生效后再使NacosServiceRegistryAutoConfiguration这个配置类生效。
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class,
NacosDiscoveryAutoConfiguration.class })
第五步查看NacosServiceRegistryAutoConfiguration配置类的内容,可以看出,这个配置类实例化了NacosServiceRegistry、NacosRegistration、NacosAutoServiceRegistration这三个bean。其中,NacosServiceRegistry负责服务注册和反注册,NacosRegistration负责维护服务实例的基本信息,NacosAutoServiceRegistration主要是实现服务的自动注册。