我是靠谱客的博主 怡然金鱼,最近开发中收集的这篇文章主要介绍spring cloud 服务注册源码分析-nacos,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

spring cloud针对服务注册和发现仅提供了抽象(都封装在spring-cloud-commons包里),常见的实现有eureka、nacos等组件,这里主要以nacos为例进行源码分析,本文代码依赖版本

spring-cloudspring-cloud-alibaba
Hoxton.SR82.2.5.RELEASE

1. 服务注册的核心接口

AutoServiceRegistration接口:服务注册配置类,spring针对该接口实现了一个抽象类AbstractAutoServiceRegistration是服务注册的触发类。

ServiceRegistry接口:负责具体的服务注册

Registration接口:主要定义服务注册所需要的一些信息,如:本服务的服务名、ip地址端口号、元数据等等。

2. 从@EnableDiscoveryClient说起

@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
boolean autoRegister() default true;
}

主要引入了EnableDiscoveryClientImportSelector

@Order(Ordered.LOWEST_PRECEDENCE - 100)
public class EnableDiscoveryClientImportSelector
extends SpringFactoryImportSelector<EnableDiscoveryClient> {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
String[] imports = super.selectImports(metadata);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(getAnnotationClass().getName(), true));
boolean autoRegister = attributes.getBoolean("autoRegister");
if (autoRegister) {
List<String> importsList = new ArrayList<>(Arrays.asList(imports));
importsList.add(
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationConfiguration");
imports = importsList.toArray(new String[0]);
}
......省略后面代码.....
}

从上面可以看到默认开启了注册功能,向spring中注册了AutoServiceRegistrationConfiguration类。

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true)
public class AutoServiceRegistrationConfiguration {
}

这类啥也没,就启用了AutoServiceRegistrationProperties配置。

一脸懵逼…………………………

3. AutoServiceRegistrationAutoConfiguration配置类

继续寻找突破口,在spring-cloud-commons的spring.factories文件里发现EnableAutoConfiguration的参数里有AutoServiceRegistrationAutoConfiguration。

@Configuration(proxyBeanMethods = false)
@Import(AutoServiceRegistrationConfiguration.class)
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
matchIfMissing = true)
public class AutoServiceRegistrationAutoConfiguration {
@Autowired(required = false)
private AutoServiceRegistration autoServiceRegistration;
@Autowired
private AutoServiceRegistrationProperties properties;
@PostConstruct
protected void init() {
if (this.autoServiceRegistration == null && this.properties.isFailFast()) {
throw new IllegalStateException("Auto Service Registration has "
+ "been requested, but there is no AutoServiceRegistration bean");
}
}
}

发现注入的有AutoServiceRegistration接口,并在构造完成后对AutoServiceRegistration做了不为空的校验.

4. Nacos服务注册接口的实现

4.1. NacosAutoServiceRegistration实现类

NacosAutoServiceRegistration继承AbstractAutoServiceRegistration类。
先看看AbstractAutoServiceRegistration

public abstract class AbstractAutoServiceRegistration<R extends Registration>
implements AutoServiceRegistration, ApplicationContextAware,
ApplicationListener<WebServerInitializedEvent> {
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() {
……………………
// only initialize if nonSecurePort is greater than 0 and it isn't already running
// because of containerPortInitializer below
if (!this.running.get()) {
……………………
register();//关键步骤三
……………………
}
}
protected void register() {
this.serviceRegistry.register(getRegistration());//关键步骤四
}
}

顺着上面的关键步骤可以知道spring在web容器初始化完成后会出发服务注册的操作。接着看具体实现类NacosAutoServiceRegistration

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;
}
}

从构造方法可以看出已将serviceRegistry和registration赋值。

4.2. NacosServiceRegistry类和NacosRegistration类

NacosServiceRegistry实现接口ServiceRegistry,

public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
}
@Override
public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) {
log.warn("No service to register for nacos client...");
return;
}
NamingService namingService = namingService();
String serviceId = registration.getServiceId();
String group = nacosDiscoveryProperties.getGroup();
Instance instance = getNacosInstanceFromRegistration(registration);
try {
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);
}
}

这个类实现了nacos的注册逻辑

4.3. Nacos服务注册接口实现类的创建

上面讲了Nacos服务注册接口实现类的作用,在哪创建的呢?

spring-cloud-starter-alibaba-nacos-discovery包的spring.factories 里有

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration,
com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,
com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,
com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration,
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,
com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,
com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,
com.alibaba.cloud.nacos.NacosServiceAutoConfiguration

打开NacosServiceRegistryAutoConfiguration

@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);
}
@Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
public NacosAutoServiceRegistration nacosAutoServiceRegistration(
NacosServiceRegistry registry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
return new NacosAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
}
}

可以看到引入该包后后,在spring.cloud.service-registry.auto-registration.enabled开关开启后就会自动创建

5. nacos的心跳机制(nacos-client-1.4.1)

服务注册到服务中心后,nacos注册中心维护了一个客户端的列表。
看看BeatReactor这个线程类:

public class BeatReactor implements Closeable {
……………………………………
class BeatTask implements Runnable {
BeatInfo beatInfo;
public BeatTask(BeatInfo beatInfo) {
this.beatInfo = beatInfo;
}
@Override
public void run() {
if (beatInfo.isStopped()) {
return;
}
long nextTime = beatInfo.getPeriod();
try {
JsonNode result = serverProxy.sendBeat(beatInfo, BeatReactor.this.lightBeatEnabled);
long interval = result.get("clientBeatInterval").asLong();
boolean lightBeatEnabled = false;
if (result.has(CommonParams.LIGHT_BEAT_ENABLED)) {
lightBeatEnabled = result.get(CommonParams.LIGHT_BEAT_ENABLED).asBoolean();
}
BeatReactor.this.lightBeatEnabled = lightBeatEnabled;
if (interval > 0) {
nextTime = interval;
}
int code = NamingResponseCode.OK;
if (result.has(CommonParams.CODE)) {
code = result.get(CommonParams.CODE).asInt();
}
if (code == NamingResponseCode.RESOURCE_NOT_FOUND) {
Instance instance = new Instance();
instance.setPort(beatInfo.getPort());
instance.setIp(beatInfo.getIp());
instance.setWeight(beatInfo.getWeight());
instance.setMetadata(beatInfo.getMetadata());
instance.setClusterName(beatInfo.getCluster());
instance.setServiceName(beatInfo.getServiceName());
instance.setInstanceId(instance.getInstanceId());
instance.setEphemeral(true);
try {
serverProxy.registerService(beatInfo.getServiceName(),
NamingUtils.getGroupName(beatInfo.getServiceName()), instance);
} catch (Exception ignore) {
}
}
} catch (NacosException ex) {
NAMING_LOGGER.error("[CLIENT-BEAT] failed to send beat: {}, code: {}, msg: {}",
JacksonUtils.toJson(beatInfo), ex.getErrCode(), ex.getErrMsg());
}
executorService.schedule(new BeatTask(beatInfo), nextTime, TimeUnit.MILLISECONDS);
}
}
………………………………
}

executorServiceScheduledExecutorService,定时的执行BeatTask这个任务,心跳的间隔时间从心跳接口中获取,当前版本为5秒一次。如果心跳接口返回没有发现该服务nacaos会再次注册服务。

最后

以上就是怡然金鱼为你收集整理的spring cloud 服务注册源码分析-nacos的全部内容,希望文章能够帮你解决spring cloud 服务注册源码分析-nacos所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(31)

评论列表共有 0 条评论

立即
投稿
返回
顶部