深度剖析Spring Cloud Alibaba系列——适配Spring Cloud和Nacos的服务元数据

2022-09-23 17:19:30 浏览数 (1)

Spring Cloud Alibaba致力于提供微服务开发的一站式解决方案,它是Spring Cloud组件被植入Alibaba元素之后的产物。利用Spring Cloud Alibaba,可以快速搭建微服务架构并完成技术升级。中小企业如果需要快速落地业务中台和技术中台,并向数字化业务转型,那Spring Cloud Alibaba绝对是一个“神器”。

本系列将带着大家一起鸟瞰Spring Cloud Alibaba注册中心,从而熟悉它的注册中心架构及相关原理。

回忆一下什么是元数据

咱们试着这样想一下,无论是我们使用Dubbo还是Spring Cloud,又或是Spring Cloud Alibaba,甚至很多公司自研的服务治理的框架,当然还有一些中间件框架,比如RocketMQ。它们都有一个统一的领域概念“元数据”,其实了可以将元数据理解为框架的基础数据,其他任何功能模块的业务都是长在“元数据”之上的。

我们就用Nacos注册中心来举例子,Nacos的元数据主要包含Nacos数据(如配置和服务)的描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义的标签(label)。从作用范围来看,元数据分为服务元数据、集群元数据及实例元数据。

Spring Cloud只是一个基础的微服务框架,它底层是整合了Consul、Zookeeper以及Eureka的注册中心,所以为了兼容这个三个注册中心,Spring Cloud定义了一套“基于Spring Cloud”的元数据中心标准。

这么说,Nacos注册中心的元数据和Spring Cloud的元数据是不兼容的,试着想一下也是这个道理,Nacos是一个独立的云原生服务治理和分布式配置管理的平台,它不可能单独的为Spring Cloud做定制化的开发,所以呢需要有框架去解决这些问题。

于是Spring Cloud Alibaba来了,它专门是来解决Nacos元数据和Spring Cloud元数据的兼容性问题的。

如何适配Spring Cloud 和Nacos的元数据

好吧,既然我们已经知道Spring Cloud Alibaba已经解决了元数据适配的问题,我们先从方法论的角度来看。

既然Spring Cloud定义了一套元数据标准,那么肯定要在它的基础之上去扩展,那么从Java语言的角度去看,能够满足扩展的最快的方式是接口和接口的实现,也就是说Spring Cloud肯定是定义了接口,让开发人员自己去实现,然后将实现类注入到Spring IOC容器中,这样才能满足Spring Cloud兼容不同注册中心的元数据标准。

好吧,听起来确实是很有道理,我们还是看看部分源码,毕竟我们是35岁程序员。

我们仔细的看看Spring Cloud Alibaba封装的两个NacosRegistration类和NacosServiceRegistry类,这个是非常关键的适配类,要仔细阅读源码。

第一步看看NacosServiceRegistry类,如下。

代码语言:javascript复制
//为了方便大家看代码设计的思想,这里就省略了大部分代码,保留代码骨架
public class NacosServiceRegistry implements ServiceRegistry<Registration> {       //实现了Spring Cloud的ServiceRegistry类的register()方法
    @Override
    public void register(Registration registration) {}
    //实现了Spring Cloud的ServiceRegistry类的deregister()方法
    @Override
    public void deregister(Registration registration) {}
}

我们重点看register()方法和deregister()方法的入参,它是Spring Cloud的Registration 类。

第二步,我们再仔细看看NacosRegistration类,如下。

代码语言:javascript复制
//为了方便大家看代码设计的思想,这里就省略了大部分代码,保留代码骨架
public class NacosRegistration implements Registration, ServiceInstance {
    //NacosRegistration类实现了Spring Cloud的Registration类和ServiceInstance 类
    //下面这些就更加熟悉,这个不就是服务元数据的属性吗。
    //什么服务ID、host、port等,这些太熟悉了
@Override
    public String getServiceId() {
        return nacosDiscoveryProperties.getService();
    }
    @Override
    public String getHost() {
        return nacosDiscoveryProperties.getIp();
    }
    @Override
    public int getPort() {
        return nacosDiscoveryProperties.getPort();
    }
    public void setPort(int port) {
        this.nacosDiscoveryProperties.setPort(port);
    }
    ...
}

那么看到NacosRegistration类之后是不是就恍然大悟,会不会NacosRegistration类注入到Spring IOC容器之后,会作为NacosServiceRegistry类的入参呢?好吧,带着问题我们再看看确认下是不是这样的设计原理。

于是我们打开Spring Cloud的AbstractAutoServiceRegistration类

代码语言:javascript复制
public abstract class AbstractAutoServiceRegistration<R extends Registration>
        implements AutoServiceRegistration, ApplicationContextAware,
        ApplicationListener<WebServerInitializedEvent> {
    protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry,
            AutoServiceRegistrationProperties properties) {
        this.serviceRegistry = serviceRegistry;
        this.properties = properties;
    }
    //使用接口ServiceRegistry的实现类的方法register()完成注册,元数据是通过方法getRegistration()获取的
    /**
     * Register the local service with the {@link ServiceRegistry}.
     */
    protected void register() {
        this.serviceRegistry.register(getRegistration());
    }
     //使用接口ServiceRegistry的实现类的方法deregister()完成注册,元数据是通过方法getRegistration()获取的
    /**
     * De-register the local service with the {@link ServiceRegistry}.
     */
    protected void deregister() {
        this.serviceRegistry.deregister(getRegistration());
    }
    ...
}

我们再回过头看看这个不就是Spring Cloud Alibaba定义的两个实现类NacosRegistration类和NacosServiceRegistry类。

好吧我们再看看是如何注入到Spring Cloud的AbstractAutoServiceRegistration类中的。

我们可以打开Spring Cloud Alibaba的NacosAutoServiceRegistration类,它继承了Spring Cloud的AbstractAutoServiceRegistration类。

代码语言:javascript复制
public class NacosAutoServiceRegistration
        extends AbstractAutoServiceRegistration<Registration> {

    private static final Logger log = LoggerFactory
            .getLogger(NacosAutoServiceRegistration.class);
    private NacosRegistration registration;
    //通过构造函数注入了NacosRegistration类和和NacosServiceRegistry类
    public NacosAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
            AutoServiceRegistrationProperties autoServiceRegistrationProperties,
            NacosRegistration registration) {
        super(serviceRegistry, autoServiceRegistrationProperties);
        this.registration = registration;
    }
    //重写了AbstractAutoServiceRegistration类的getRegistration()方法,让Spring Cloud能够获取Spring Cloud Alibaba自定义的NacosRegistration类
    @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;
    }

}

这样大家是不是就非常熟悉Nacos和Spring Cloud的元数据是如何整合和适配的了。‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

总结

本文带着大家熟悉了Nacos和Spring Cloud的元数据整合的代码细节。


下一期:将会从架构设计的角度去分析Nacos和Spring Cloud的元数据整合。


0 人点赞