如何实现服务自动注册

25 篇文章 3 订阅
12 篇文章 1 订阅

1. 背景


接着上次的说,Nacos问题的分析。这次就来分享一下自己的分析方法。以及如何利用Spring事件完成服务注册。

2. 分析一下


2.1 问题分析过程


问题是这样的,我以为是Nacos服务注册不上吗?那就肯定是注册有问题了, 那就去找是服务是如何注册的。

关键是从哪找呢?具体步骤:


知道服务启动方式。如Nacos,就是通过properties,那就找哪有用到启动的属性文件
项目用SpringBoot集成,那核心类的加载就在Spring.factories中。(这个文件会被springSPI加载到)
找到关键类

很凑巧,我们在spring.factories中找到了名字很像启动注册类的类。如下图:

在找类的时候不要怕错,大胆猜,只要验证了自己的想法即可,不对就在接着找。

​​com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration​​类我们找到了,接下来就是去看这个类中的代码去验证自己的想法了。

2.2 Nacos是如何利用Spring事件来实现服务注册的?


​​com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration​​代码如下:

public class NacosServiceRegistryAutoConfiguration {
// 注册类实现,验证我们的想法,需要用到NacosDiscoverProperties
@Bean
public NacosServiceRegistry nacosServiceRegistry(
NacosDiscoveryProperties nacosDiscoveryProperties) {
return new NacosServiceRegistry(nacosDiscoveryProperties);
  }
// 构建注册事例,依然要用到NacosDiscoverProperties
@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);

通过查看代码,发现和我们猜想没有出入,是通过​​NacosDiscoverProperties​​来进行初始化,和官方给的Demo也相似(只是没继承SpringBoot,名字不叫这个),前面两个类我们先不用关注(好奇的可以先点进去看看),我们直接进入第三个方法​​NacosAutoServiceRegistration​​中,通过名字我们也可以看出,这个是自动注册的,参数中包含了Registry和Registration。我们进入类中接着查看。

public class NacosAutoServiceRegistration
extends AbstractAutoServiceRegistration<Registration> {
private NacosRegistration registration;
// 构造参数,关键
public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties,
NacosRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration;
  }
// 注册方法
@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();
  }
进入类中,我们发现了register()方法,更进一步验证我们想法,是通过这个类来进行服务注册,但是在register()方法中,调用了父类的register()方法, 这点就要引起我们的好奇,父类都没都啥东西,调用父类的方法有啥用呢?这个时候就想到了肯定有构造参数,或者方法初始化父类的东西啦!

我们观察构造参数,发现把serviceRegistry传入到了父类构造参数中,我们直接查看父类代码。

// 类
public abstract class AbstractAutoServiceRegistration<R extends Registration>

    implements AutoServiceRegistration, ApplicationContextAware,

    ApplicationListener<WebServerInitializedEvent> {
}
AbstractAutoServiceRegistration​​是继承了​​ApplicationListener<WebServerInitializedEvent>​​,看到这,不就是我们熟悉的领域了吗?继承了​​ApplicationListener​​那就不多BB,直接看​​onApplicationEvent()​​方法就好啦。(这个事件是WebServerInitializedEvent,这点还是要知道的哈)

  @Override
  @SuppressWarnings("deprecation")
  public void onApplicationEvent(WebServerInitializedEvent event) {
    // 调用了bind方法
    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());
    // 调用了start()方法
    this.start();
  }

我们直接进入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();
// 服务注册事件
this.context.publishEvent(
new InstanceRegisteredEvent<>(this, getConfiguration()));
this.running.compareAndSet(false, true);
    }

start()方法里面还发布了两个事件,可见Spring中,服务的注册前后都有一些监听器来处理服务信息。先跳过这些,我们直接关注我们的核心——注册,直接进入register()方法中。

protected void register() {
// this.serviceRegistry 是我们传递进来的,
// getRegistration() 是在NacosAutoServiceRegistration中实现的
this.serviceRegistry.register(getRegistration());

5.
到这我们基本知道是怎么回事了,​​this.serviceRegistry​​是传递进来的,那调用的​​register()​​方法则是Nacos自己实现的注册,​​getRegistration()​​是​​NacosServiceRegistryAutoConfiguration​​中通过​​nacosDiscoveryProperties​​生成的。那我们就看一下​​register()​​方法就好啦。

@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();
    // 通过registration构建Instance实例
    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);
    }
  }

3. 吸星大法:吸收代码经验


Spring 在实现的时候,通过设计模式(装饰),实现流程,又把关键部分丢给开发自己实现,提高了拓展性,然后巧妙的结合了观察者模式(变种),在合适的时间注册服务,妙啊~~

Nacos在实现的时候,深知Spring各种属性,各种用法,一定是对Spring有个深入了解的人(或者正好看过?这个解释有点牵强),结合AutoRegistry和事件(不知道,肯定不知道怎么调用的),妙啊~~

看到这实现的代码,简直舒服,妙啊~~  

4. 总结
总的看下来,这个启动,只能有Web容器的时候才能注册, 我猜主要是和namingServer注册有关,所以也不能算是一个bug了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值