dubbo解析-详解MetadataService

本文基于dubbo 2.7.5版本代码

在上一篇文章《dubbo解析-详解元数据中心MetadataReport》介绍了元数据中心如何启动,如何配置。这篇文章介绍一个和元数据中心密切相关的接口MetadataService。可以这么说没有MetadataService,元数据中心就无法正常使用。上一篇文章介绍的AbstractMetadataReport类里面的方法几乎都是MetadataService实现类RemoteWritableMetadataService调用的。MetadataService与MetadataReport之间的关系如下图:
在这里插入图片描述

一、MetadataService

MetadataService有多个实现类:
在这里插入图片描述
RemoteMetadataServiceProxy应用于服务发现,以后文章介绍。
从上图中可以看到WritableMetadataService扩展了接口MetadataService。
本文主要分析WritableMetadataService的实现类:InMemoryWritableMetadataService和RemoteWritableMetadataService、RemoteWritableMetadataServiceDelegate。
下面介绍MetadataService对象在哪里创建的。
先看服务端。服务端是在服务暴露完成后通过SPI加载的WritableMetadataService对象。如果服务只在本地暴露,那么dubbo不会创建WritableMetadataService对象。

			if (!SCOPE_REMOTE.equalsIgnoreCase(scope)) {
                exportLocal(url);//在本地暴露服务,当消费端和服务端在同一个dubbo实例时使用
            }
            //将服务暴露到外部,消费端可以通过网络访问到该服务
            if (!SCOPE_LOCAL.equalsIgnoreCase(scope)) {
                if (CollectionUtils.isNotEmpty(registryURLs)) {
                	//。。。。
                    //代码删除,删除的代码主要做将服务通过网络发布出去,将服务注册到注册中心
                }
                //服务暴露完成后,检查metadata配置,通过SPI加载对应的WritableMetadataService对象
                WritableMetadataService metadataService = WritableMetadataService.getExtension(url.getParameter(METADATA_KEY, DEFAULT_METADATA_STORAGE_TYPE));
                if (metadataService != null) {
                	//服务定义发布,可以将服务定义发布到元数据中心
                    metadataService.publishServiceDefinition(url);
                }
            }

再来看消费端。代码可以参见类ReferenceConfig的createProxy方法。在createProxy方法中,当消费端创建完成远程服务代理对象后,便执行下面代码创建WritableMetadataService对象,并做服务定义的发布:

		String metadata = map.get(METADATA_KEY);
        WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? DEFAULT_METADATA_STORAGE_TYPE : metadata);
        if (metadataService != null) {
            URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
            //服务定义发布,可以将服务定义发布到元数据中心
            metadataService.publishServiceDefinition(consumerURL);
        }

消费端的代码与服务端基本一样。
其中两者都使用了下面的代码加载WritableMetadataService对象:

WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? DEFAULT_METADATA_STORAGE_TYPE : metadata);

代码中的metadata属性是在@Servcie(parameters={“metadata”,“remote”})或者@Reference(parameters={“metadata”,“remote”})中配置的。metadata只有两个值:

  • local(默认值)
  • remote

如果metadata=local,那么SPI加载的类是InMemoryWritableMetadataService,如果metadata=remote,则类是RemoteWritableMetadataServiceDelegate。对应关系可以参见文件org.apache.dubbo.metadata.WritableMetadataService。
我个人认为metadata的设置方式不合理,如果每个服务接口都使用元数据中心,那么每个@Reference和@Servcie都要设置,这样工作量太大了。dubbo应该提供以applicantion或者module级别的参数设置。

二、InMemoryWritableMetadataService

从名字上可以看出来,这个类的数据都存储在内存中。
该类主要属性有三个:

  • serviceDefinitions:保存服务接口定义。该属性是Map对象。key是接口名+分组+version,value是json格式的ServiceDefinition对象。
  • subscribedServiceURLs:存储服务端发布的服务参数和消费端引用的服务参数,包括IP地址,路由规则等。也是Map对象。key值同上。value是由参数组成的URL对象。
  • exportedServiceURLs:存储的内容与subscribedServiceURLs类似。

后面两个属性与服务发现功能相关。
该类主要是操作上述三个属性,当服务发布或者创建服务代理时,将对应的信息存储到三个属性中。代码比较简单不再展示,有兴趣的可以看代码。

三、RemoteWritableMetadataServiceDelegate

当metadata设置为remote时,SPI加载该类。下面看一下该类的构造方法:

	public RemoteWritableMetadataServiceDelegate() {
		//加载InMemoryWritableMetadataService
        defaultWritableMetadataService = (InMemoryWritableMetadataService) WritableMetadataService.getExtension("local");
        //创建RemoteWritableMetadataService,入参是InMemoryWritableMetadataService
        remoteWritableMetadataService = new RemoteWritableMetadataService(defaultWritableMetadataService);
    }

在构造方法中,创建了InMemoryWritableMetadataService和RemoteWritableMetadataService两个对象。InMemoryWritableMetadataService负责读写本地内存,RemoteWritableMetadataService负责修改远程数据。
该类中修改类型的方法都直接调用InMemoryWritableMetadataService和RemoteWritableMetadataService的方法。查询类型的方法是调用对应的InMemoryWritableMetadataService的方法。
修改数据时,同时修改两个对象,使两个对象数据保持一致,查询时只查询本地内存,加快查询速度。

三、RemoteWritableMetadataService

该类是将服务信息保存到远程,比如zk,redis等。具体保存到哪里,取决于MetadataReport的实现。下面介绍各个方法的作用。

1、refreshMetadata

该方法主要是在服务发现的场景中使用,是由事件ServiceInstancePreRegisteredEvent触发。其入参可以理解为版本号,代码里面将入参版本号与当前RemoteWritableMetadataService对象里面的版本号作对比,不相等时会将InMemoryWritableMetadataService中的数据通过MetadataReport对象传输到元数据中心。
通过对代码的分析,因为入参版本号设的值都是null,该方法判断入参为null后,直接返回,不访问元数据中心。

2、publishServiceDefinition

该方法用于保存服务接口元数据信息。服务端发布服务、客户端创建代理时都会调用该方法。该方法再调用MetadataReport的storeProviderMetadata方法将数据存储到元数据中心。

public void publishServiceDefinition(URL providerUrl) {
        try {
        	//获取服务接口名
            String interfaceName = providerUrl.getParameter(INTERFACE_KEY);
            if (StringUtils.isNotEmpty(interfaceName)
                    && !ProtocolUtils.isGeneric(providerUrl.getParameter(GENERIC_KEY))) {
                Class interfaceClass = Class.forName(interfaceName);
                //构建服务接口的ServiceDefinition对象
                ServiceDefinition serviceDefinition = ServiceDefinitionBuilder.build(interfaceClass);
                //将ServiceDefinition发布到元数据中心
                getMetadataReport().storeProviderMetadata(new MetadataIdentifier(providerUrl.getServiceInterface(),
                        providerUrl.getParameter(VERSION_KEY), providerUrl.getParameter(GROUP_KEY),
                        null, null), serviceDefinition);
                return;
            }
        } catch (ClassNotFoundException e) {
            //代码删减
        }
        publishProvider(providerUrl);
    }

3、publishProvider

该方法与publishServiceDefinition功能类似,两个方法都调用MetadataReport的storeProviderMetadata方法。区别在于,publishProvider除了将ServiceDefinition对象发布到元数据中心外,还把配置文件、@Service等设置的参数一并发布到元数据中心。

四、总结

通过上面的分析可以看出,MetadataService主要在服务发现功能中使用,这也是dubbo服务自省的设计要求。后面的文章会介绍服务发现。
另外,在spring发布ContextRefreshedEvent事件之后,MetadataServiceExporter可以将MetadataService对象以dubbo服务的形式发布出去,这样可以通过网络访问到dubbo实例的元数据信息。但是不是任何时候都可以发布成功的,需要InMemoryWritableMetadataService的属性exportedServiceURLs不为空才行,这个属性与服务发现有关,以后介绍。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值