- 一、前言
- 二、DubboBootstrap
- 1. 构造函数
- 三、DubboBootstrap#start
- 1. 服务初始化
- 1.1 ApplicationModel.iniframeworkExts()
- 1.2 startConfigCenter()
- 1.3 useRegistryAsConfigCenterIfNecessary()
- 1.4 startmetadataReport();
- 1.5. loadRemoteConfigs()
- 1.6 checkGlobalConfigs()
- 1.7 initmetadataService()
- 1.8 initmetadataServiceExporter()
- 1.9 initEventListener()
- 2. 服务导出
- 3. 服务自省
- 4. 服务引用
- 四、DubboBootstrap#stop
- 五、2.7.5 流程简介
- 1. 提供者
- 1.1 ServiceConfig#export
- 1.2 ServiceConfig#doExport
- 1.3 ServiceConfig#doExportUrls
- 2. 消费者:
- 2.1 ReferenceConfig#get
- 2.2 ReferenceConfig#init
本系列为个人Dubbo学习笔记,内容基于《深度剖析Apache Dubbo 核心技术内幕》, 过程参考官方源码分析文章,仅用于个人笔记记录。本文分析基于Dubbo2.7.0版本,由于个人理解的局限性,若文中不免出现错误,感谢指正。
系列文章地址:Dubbo源码分析:全集整理
本文基于 Dubbo 2.7.5 版本。
在 Dubbo笔记㉕ : Spring 执行流程概述 一文中,我们介绍了 在 Spring 中 Dubbo 的执行流程,其中我们知道了 提供者在启动时的服务发布是在 DubboBootstrap 中完成的。本文我们来看一下 DubboBootstrap 的执行流程。
二、DubboBootstrapDubboBootstrap 是 Dubbo 服务启动的核心类,在其中完成了Dubbo服务暴露的过程。
1. 构造函数DubboBootstrap 是单例的,其构造函数如下:
private DubboBootstrap() {
// 获取 配置管理
configManager = ApplicationModel.getConfigManager();
// 获取 环境
environment = ApplicationModel.getEnvironment();
DubboShutdownHook.getDubboShutdownHook().register();
// 设置回调,当服务关闭时触发该回调,调用 DubboBootstrap#destroy 来销毁服务。
ShutdownHookCallbacks.INSTANCE.addCallback(new ShutdownHookCallback() {
@Override
public void callback() throws Throwable {
DubboBootstrap.this.destroy();
}
});
}
三、DubboBootstrap#start
DubboBootstrap#start 的实现如下:
public DubboBootstrap start() {
// cas 保证只启动一次
if (started.compareAndSet(false, true)) {
// 1. 服务配置初始化
initialize();
// 2. Dubbo服务导出
exportServices();
// Not only provider register
// 3. 元数据中心服务暴露,当使用服务自省模式时才会执行该部分逻辑
// 3.1 不仅仅提供者注册 || 存在导出的服务
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// 3.2 导出元数据服务
exportmetadataService();
// 3.3 如果需要注册本地服务实例
registerServiceInstance();
}
// 4. 服务引用流程
referServices();
}
return this;
}
下面我们按照注释顺序来看:
1. 服务初始化在 DubboBootstrap#initialize 中完成了 Dubbo的配置检查和初始化,其具体实现如下:
private void initialize() {
// CAS 防止多次调用
if (!initialized.compareAndSet(false, true)) {
return;
}
// 1. 初始化 frameworkExt 扩展类。 frameworkExt 是 SPI接口,这里获取所有的 实现类并且调用frameworkExt#initialized 来初始化
ApplicationModel.iniframeworkExts();
// 2. 启用配置中心并刷新本地配置
startConfigCenter();
// 3. 在默认是zk作为注册中心时,如果没有配置配置中心,则使用注册中心作为配置中心
useRegistryAsConfigCenterIfNecessary();
// 4. 启动元数据中心配置
startmetadataReport();
// 5. 加载远程配置
loadRemoteConfigs();
// 6. 检查本地配置是否合法
checkGlobalConfigs();
// 7. 初始化元数据中心 Service
initmetadataService();
// 8. 初始化元数据中心导出类
initmetadataServiceExporter();
// 9. 初始化监听器
initEventListener();
}
在 Spring 中 Dubbo 的初始化工作和 Main 方法启动基本也是类似的,只不过在执行过程中稍微有些区别。下面我们按照注释来具体说明 :
1.1 ApplicationModel.iniframeworkExts()ApplicationModel.iniframeworkExts() 是执行框架扩展实现类的初始化方法,其实现如下:
public static void iniframeworkExts() {
// 获取支持的框架扩展frameworkExt 实现
Set exts = ExtensionLoader.getExtensionLoader(frameworkExt.class).getSupportedExtensionInstances();
for (frameworkExt ext : exts) {
// 执行初始化方法
ext.initialize();
}
}
其中 frameworkExt 是 Dubbo 提供的 框架扩展 SPI 接口,继承了 Lifecycle 接口,如下:
@SPI
public interface frameworkExt extends Lifecycle {
}
...
// Lifecycle 接口实现如下
public interface Lifecycle {
void initialize() throws IllegalStateException;
void start() throws IllegalStateException;
void destroy() throws IllegalStateException;
}
Lifecycle 是 Dubbo 组件的声明周期接口,SPI 扩展实现类时在对应的生命周期会调用对应的方法。
-
Lifecycle#initialize :当一个 SPI 实现类实现 Lifecycle 接口时,在其创建时会调用该方法。
-
Lifecycle#start :当一个 SPI 实现类实现 Lifecycle 接口时,在容器刷新结束后会调用该方法。
-
Lifecycle#destroy :当一个 SPI 实现类实现 Lifecycle 接口时,在容器销毁时会调用该方法。
Dubbo 提供的frameworkExt 有三个实现 : ConfigManager、Environment、ServiceRepository。我们这里先来看 initialize 方法。只有 Environment#initialize 有具体操作,如下:
// 加载了配置中心的配置并保存到了 org.apache.dubbo.common.config.Environment 的 map 中。
@Override
public void initialize() throws IllegalStateException {
// 获取 配置管理
ConfigManager configManager = ApplicationModel.getConfigManager();
// 获取默认的配置中心
Optional> defaultConfigs = configManager.getDefaultConfigCenter();
// 如果存在配置中心,则从配置中心获取配置,保存到本地。
defaultConfigs.ifPresent(configs -> {
for (ConfigCenterConfig config : configs) {
this.setExternalConfigMap(config.getExternalConfiguration());
this.setAppExternalConfigMap(config.getAppExternalConfiguration());
}
});
}
1.2 startConfigCenter()
如果存在配置中心,则会在这里加载了配置中心的配置与本地配置合并,并保存到 environment 中。
private void startConfigCenter() {
Collection configCenters = configManager.getConfigCenters();
if (CollectionUtils.isNotEmpty(configCenters)) {
// 复合配置,保存了配置优先级的特性
CompositeDynamicConfiguration compositeDynamicConfiguration = new CompositeDynamicConfiguration();
for (ConfigCenterConfig configCenter : configCenters) {
// 刷新配置中心配置
configCenter.refresh();
ConfigValidationUtils.validateConfigCenterConfig(configCenter);
// 添加到 复合配置中
compositeDynamicConfiguration.addConfiguration(prepareEnvironment(configCenter));
}
environment.setDynamicConfiguration(compositeDynamicConfiguration);
}
// 刷新本地配置
configManager.refreshAll();
}
关于配置中心的内容,如有需要详参:Dubbo笔记 ㉒ :配置中心
1.3 useRegistryAsConfigCenterIfNecessary()这一步的注释很清楚,就不再贴出代码:出于兼容性考虑,当注册协议是zookeeper并且没有明确指定配置中心时,使用注册中心作为默认配置中心。
1.4 startmetadataReport();初始化元数据中心实例。服务如果配置了元数据中心, 则在此处进行配置初始化
private void startmetadataReport() {
ApplicationConfig applicationConfig = getApplication();
// 获取元数据中心类型,local 或 remote
String metadataType = applicationConfig.getmetadataType();
// FIXME, multiple metadata config support.
Collection metadataReportConfigs = configManager.getmetadataConfigs();
if (CollectionUtils.isEmpty(metadataReportConfigs)) {
// 如果配置是 元数据中心是远程 (dubbo.application.metadata-type = remote) && 没配置元数据中心 则抛出异常
if (REMOTE_metaDATA_STORAGE_TYPE.equals(metadataType)) {
throw new IllegalStateException("No metadataConfig found, you must specify the remote metadata Center address when 'metadata=remote' is enabled.");
}
// 如果没有配置元数据中心则直接返回
return;
}
// 获取元数据中心配置
metadataReportConfig metadataReportConfig = metadataReportConfigs.iterator().next();
// 校验配置
ConfigValidationUtils.validatemetadataConfig(metadataReportConfig);
if (!metadataReportConfig.isValid()) {
return;
}
// metadataReportInstance 会根据元数据中心的配置,创建一个 metadataReport 实例。
// metadataReportInstance#metadataReport 是静态的属性,所以对于metadataReportInstance 来说 只会存在一个 metadataReport
metadataReportInstance.init(metadataReportConfig.toUrl());
}
1.5. loadRemoteConfigs()
这一步 对 RegistryConfig 和 ProtocolConfig 的 id 进行了处理。
private void loadRemoteConfigs() {
// registry ids to registry configs
List tmpRegistries = new ArrayList<>();
// 获取 registry id
Set registryIds = configManager.getRegistryIds();
registryIds.forEach(id -> {
if (tmpRegistries.stream().noneMatch(reg -> reg.getId().equals(id))) {
// 通过 registry id 获取到对应的 RegistryConfig 并刷新配置
tmpRegistries.add(configManager.getRegistry(id).orElseGet(() -> {
// 设置注册中心配置的id
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setId(id);
registryConfig.refresh();
return registryConfig;
}));
}
});
// 保存经过上述处理的注册中心
configManager.addRegistries(tmpRegistries);
// protocol ids 同上
// protocol ids to protocol configs
List tmpProtocols = new ArrayList<>();
Set protocolIds = configManager.getProtocolIds();
protocolIds.forEach(id -> {
if (tmpProtocols.stream().noneMatch(prot -> prot.getId().equals(id))) {
tmpProtocols.add(configManager.getProtocol(id).orElseGet(() -> {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setId(id);
protocolConfig.refresh();
return protocolConfig;
}));
}
});
configManager.addProtocols(tmpProtocols);
}
1.6 checkGlobalConfigs()
这一步是检查各个组件的配置是否正确,逻辑比较常规,篇幅所限不再贴出代码。
1.7 initmetadataService()这里会初始化元数据服务 metadataService, 当使用服务自省时会注册该服务。
private void initmetadataService() {
this.metadataService = getExtension(getmetadataType());
}
这里会根据 dubbo.application.metadata-type 参数的不同,metadataService 会选择不同的实现。
metadataService 的子接口 WritablemetadataService 具有三个实现类 :
- InMemoryWritablemetadataService : 实现在导出时将 Dubbo 服务的元数据存储在本地内存中。当 metadata-type = local 时加载该类作为元数据服务,服务的元数据信息会保存在本地。
- RemoteWritablemetadataService : 实现在导出时将 Dubbo 服务的元数据存储在元数据中心。会通过 metadataReport 将服务元数据写到元数据中心
- RemoteWritablemetadataServiceDelegate :在 RemoteWritablemetadataServiceDelegate 中,针对于元数据的操作会同时执行 RemoteWritablemetadataService 和 InMemoryWritablemetadataService 对应方法。当 metadata-type = remote 时加载该类作为元数据服务
初始化元数据中心服务导出器,metadataServiceExporter 用于导出 metadataService,其实现如下:
private void initmetadataServiceExporter() {
this.metadataServiceExporter = new ConfigurablemetadataServiceExporter(metadataService);
}
1.9 initEventListener()
初始化事件监听方法,
// Dubbo 提供了 DirectEventDispatcher 和 ParallelEventDispatcher两种实现,默认是 DirectEventDispatcher
private final EventDispatcher eventDispatcher = EventDispatcher.getDefaultExtension();
private void initEventListener() {
// Add current instance into listeners
addEventListener(this);
}
public DubboBootstrap addEventListener(EventListener> listener) {
eventDispatcher.addEventListener(listener);
return this;
}
EventDispatcher 是 SPI 接口,Dubbo提供了两个实现 :
- DirectEventDispatcher :使用当前调用线程来进行实现分发,该类是默认事件分发策略。
- ParallelEventDispatcher : 使用 ForkJoinPool.commonPool(); 线程池来进行事件分发。
DubboBootstrap 是 GenericEventListener 子类,实现了泛化监听的功能。
2. 服务导出DubboBootstrap#exportServices 开始实际导出服务,其实现如下:
private void exportServices() {
// configManager.getServices() 获取所有需要发布的Dubbo Service
configManager.getServices().forEach(sc -> {
// TODO, compatible with ServiceConfig.export()
ServiceConfig serviceConfig = (ServiceConfig) sc;
serviceConfig.setBootstrap(this);
// 如果是异步发布,则交由线程池来发布,并将 Future 保存到 asyncExportingFutures 中
if (exportAsync) {
ExecutorService executor = executorRepository.getServiceExporterExecutor();
Future> future = executor.submit(() -> {
sc.export();
});
asyncExportingFutures.add(future);
} else {
// 服务发出,导出的服务保存到exportedServices 中
sc.export();
exportedServices.add(sc);
}
});
}
这里需要注意 configManager.getServices() 获取到的是所有要发布的 dubbo 服务的 ServiceBean。
在 Dubbo笔记㉕ : Spring 执行流程概述 一文中我们说到,在 Spring 中需要暴露的服务会有一个对应的 ServiceBean 注入到容器中,而 ServiceBean 在创建时会调用父类方法AbstractConfig#addIntoConfigManager 将 当前 Bean 添加到 ConfigManager 中。而在这里,则是通过 configManager.getServices() 将所有 的 ServiceBean 拿出来暴露服务。
上面可以看到,服务实际导出过程交由了 ServiceConfig#export 来完成。而 ServiceConfig#export 的导出过程,我们在之前的文章中已经有过分析过 dubbo 2.7.0 版本,:Dubbo笔记 ③ : 服务发布流程 - ServiceConfig#export。
3. 服务自省这部分的逻辑只有在 dubbo.application.register-consumer = true 或 启用服务自省时才会执行。关于该部分的详细逻辑,我们在==服务自省的文章(尚未成文)==中详细分析,
// 3. 元数据中心服务暴露
// 3.1 dubbo.application.register-consumer = true || 通过 metadataService 暴露了服务
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// 3.2 暴露 MateService
exportmetadataService();
// 3.3 注册 应用 到注册中心
registerServiceInstance();
}
4. 服务引用
如果当前这个服务也引用了其他服务,则在这里完成其他服务的引用。
对于一个Dubbo服务,我们可以通过注解的形式来引用
-
通过 @Reference 注解引用
@Reference(group = "spring", version = "2.0.0") private ProviderService providerService; -
通过 XML 的形式引用
-
通过 @Bean 注解方式引用
@Bean public ReferenceBeanreferenceConfig(){ ReferenceBean referenceConfig = new ReferenceBean<>(); referenceConfig.setInterface(ProviderService.class); referenceConfig.setVersion("2.0.0"); referenceConfig.setGroup("spring"); return referenceConfig; }
对于第一种情况则直接通过 ReferenceAnnotationBeanPostProcessor 来完成引用,而第三种情况则是通过这里的代码完成。(第二种 XML 形式我没看逻辑 )
当 ReferenceBean 在 Spring容器中创建时会调用 AbstractConfig#addIntoConfigManager 将自身添加到 ConfigManager 的配置中。这里通过 configManager.getReferences() 获取到该 ReferenceBean 进行服务引用。具体代码如下:
private void referServices() {
// 获取 引用缓存
if (cache == null) {
cache = ReferenceConfigCache.getCache();
}
// 遍历当前应用引用的 dubbo 服务
configManager.getReferences().forEach(rc -> {
// TODO, compatible with ReferenceConfig.refer()
ReferenceConfig referenceConfig = (ReferenceConfig) rc;
referenceConfig.setBootstrap(this);
// 是否延迟初始化,默认 true,不需要延迟
if (rc.shouldInit()) {
// 异步 或 异步加载引用实例。
if (referAsync) {
CompletableFuture
其中 ReferenceConfigCache#get(ReferenceConfigbase
publicT get(ReferenceConfigbase referenceConfig) { // 获取引用的服务 key String key = generator.generateKey(referenceConfig); Class> type = referenceConfig.getInterfaceClass(); proxies.computeIfAbsent(type, _t -> new ConcurrentHashMap()); ConcurrentMap proxiesOfType = proxies.get(type); proxiesOfType.computeIfAbsent(key, _k -> { // 获取引用服务的代理类 Object proxy = referenceConfig.get(); // 缓存引用实例 referredReferences.put(key, referenceConfig); return proxy; }); // 返回引用实例 return (T) proxiesOfType.get(key); }
我们这里看到最终还是通过 Object proxy = referenceConfig.get(); 来获取的 Dubbo引用的服务代理类,关于 ReferenceConfig#get 的内容,我们在之前分析 2.7.0 的文章中已经进行过详细解析,如有需要。详参 :Dubbo笔记 ⑧ : 消费者启动流程 - ReferenceConfig#get
四、DubboBootstrap#stop当 Spring容器销毁时触发该方法,该方法则是完成一些销毁工作,具体不再赘述。
public DubboBootstrap stop() throws IllegalStateException {
destroy();
return this;
}
public void destroy() {
if (started.compareAndSet(true, false)
&& destroyed.compareAndSet(false, true)) {
unregisterServiceInstance();
unexportmetadataService();
unexportServices();
unreferServices();
destroyRegistries();
destroyProtocols();
destroyServiceDiscoveries();
clear();
shutdown();
release();
}
}
五、2.7.5 流程简介
通过我们上面的分析可以知道,提供者的服务导出是通过 ServiceConfig#export 方法实现。 消费者的服务引用是通过 ReferenceConfig#get 方法实现。关于这两个方法的执行流程我们在之前的文章中分析过 Dubbo2.7.0 版本的逻辑 (Main 方法执行版本),2.7.5 版本 (Spring 执行版本)的执行逻辑与之相差不大,下面简要介绍一下 Spring 2.7.5 版本下的执行过程。
这里仅仅是展示了一点流程,如果需要详细阅读,可参考 Dubbo源码分析:全集整理
1. 提供者 1.1 ServiceConfig#export public synchronized void export() {
// 不应暴露直接返回服务
if (!shouldExport()) {
return;
}
// bootstrap 没有初始化则先初始化
if (bootstrap == null) {
bootstrap = DubboBootstrap.getInstance();
bootstrap.init();
}
// 检查并更新配置
checkAndUpdateSubConfigs();
//init servicemetadata
// 初始化 service 元数据信息,暴露版本、分组、接口、暴露方法及入参等信息
servicemetadata.setVersion(version);
servicemetadata.setGroup(group);
servicemetadata.setDefaultGroup(group);
servicemetadata.setServiceType(getInterfaceClass());
servicemetadata.setServiceInterfaceName(getInterface());
servicemetadata.setTarget(getRef());
// 进行服务发布
if (shouldDelay()) {
DELAY_EXPORT_EXECUTOR.schedule(this::doExport, getDelay(), TimeUnit.MILLISECONDS);
} else {
doExport();
}
}
这一步主要增加了 DubboBootstrap 的初始化验证 和 Servicemetadata 的赋值
1.2 ServiceConfig#doExport protected synchronized void doExport() {
....
// 进行服务暴露
doExportUrls();
// dispatch a ServiceConfigExportedEvent since 2.7.4
// 分发暴露事件,ServiceNameMappingListener 对 ServiceConfigExportedEvent 事件进行监听
dispatch(new ServiceConfigExportedEvent(this));
}
注: dispatch(new ServiceConfigExportedEvent(this)); 会分发 ServiceConfigExportedEvent 事件。而 ServiceNameMappingListener 对该事件进行了监听。ServiceNameMappingListener#onEvent 实现如下:
@Override
public void onEvent(ServiceConfigExportedEvent event) {
ServiceConfig serviceConfig = event.getServiceConfig();
List exportedURLs = serviceConfig.getExportedUrls();
exportedURLs.forEach(url -> {
String serviceInterface = url.getServiceInterface();
String group = url.getParameter(GROUP_KEY);
String version = url.getParameter(VERSION_KEY);
String protocol = url.getProtocol();
// 在配置中心上映射服务,以 zk 为例,其映射的节点为 dubbo/config/mapping/com.kingfish.service.ProviderService/simple-provider
// 即 dubbo/config/mapping/{接口全路径}/{应用名称}
serviceNameMapping.map(serviceInterface, group, version, protocol);
});
}
1.3 ServiceConfig#doExportUrls
private void doExportUrls() {
ServiceRepository repository = ApplicationModel.getServiceRepository();
ServiceDescriptor serviceDescriptor = repository.registerService(getInterfaceClass());
// 注册服务提供者
repository.registerProvider(
getUniqueServiceName(),
ref,
serviceDescriptor,
this,
servicemetadata
);
// 获取注册中心地址
List registryURLs = ConfigValidationUtils.loadRegistries(this, true);
for (ProtocolConfig protocolConfig : protocols) {
String pathKey = URL.buildKey(getContextPath(protocolConfig)
.map(p -> p + "/" + path)
.orElse(path), group, version);
// In case user specified path, register service one more time to map it to path.
// 注册 Dubbo Service
repository.registerService(pathKey, interfaceClass);
// TODO, uncomment this line once service key is unified
servicemetadata.setServiceKey(pathKey);
// 进行服务暴露
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
关于 ServiceConfig#doExportUrlsFor1Protocol 的内容基本和 2.7.0 没有差异,详参 Dubbo笔记 ④ : 服务发布流程 - doExportUrlsFor1Protocol
下面内容来源 : dubbo解析-ServiceRepository功能及属性详解
ServiceRepository是存储了所有服务端发布的服务、客户端需要访问的服务,通过ServiceRepository可以获取所有本dubbo实例发布的服务和引用的服务。
ServiceRepository是通过ApplicationModel.getServiceRepository方法创建或者获取的。
里面包括三个字段:services、consumers、providers。作用分别是:
-
services:类型是ConcurrentMap
,key是远程服务的接口名,ServiceDescriptor是服务描述符对象,ServiceDescriptor记录了服务接口的Class对象,接口名,服务接口每个方法的名字、入参类型、返回值类型等详细信息,ServiceDescriptor可以理解为记录了远程服务接口的详细描述。客户端、服务端在启动的时候都会调用ServiceRepository.registerService方法将ServiceDescriptor对象注册到services中。下面两个属性需要的ServiceDescriptor对象也是从services中获取的。 -
consumers:类型是ConcurrentMap
,key是serviceKey,serviceKey是由服务接口+“:”+group+“:”+version组成的,ConsumerModel中也有serviceKey,除了serviceKey之外还有ServiceDescriptor、ReferenceConfig对象、MethodConfig配置信息、可以访问远程服务提供者的Invoker对象。在客户端启动的时候,dubbo会调用ReferenceConfig的init方法,在init方法里面调用ServiceRepository.registerConsumer方法,该方法会创建ConsumerModel对象,并将其注册到ServiceRepository中。之后,dubbo可以访问该consumers属性,获取所有的客户端需要访问的远程服务信息。 -
providers:类型是ConcurrentMap
,key是serviceKey,serviceKey是由服务接口+“:”+group+“:”+version组成的,ProviderModel中也有serviceKey,除了serviceKey之外还有ServiceDescriptor、ServiceConfig对象以及对外提供服务的spring bean对象。在服务端启动暴露服务的时候,dubbo会调用ServiceConfig的doExportUrls方法,在doExportUrls方法里面调用ServiceRepository.registerProvider方法,该方法会创建ProviderModel对象,并将其注册到ServiceRepository中。之后,dubbo可以访问该providers属性,获取所有服务端发布的服务信息。
public synchronized T get() {
if (destroyed) {
throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
2.2 ReferenceConfig#init
public synchronized void init() {
if (initialized) {
return;
}
// bootstrap 初始化
if (bootstrap == null) {
bootstrap = DubboBootstrap.getInstance();
bootstrap.init();
}
checkAndUpdateSubConfigs();
//init serivcemetadata
// 初始化 servicemetadata信息
servicemetadata.setVersion(version);
servicemetadata.setGroup(group);
servicemetadata.setDefaultGroup(group);
servicemetadata.setServiceType(getActualInterface());
servicemetadata.setServiceInterfaceName(interfaceName);
// TODO, uncomment this line once service key is unified
servicemetadata.setServiceKey(URL.buildKey(interfaceName, group, version));
checkStubAndLocal(interfaceClass);
ConfigValidationUtils.checkMock(interfaceClass, this);
Map map = new HashMap();
... 服务参数解析,保存到 map 中
// 将参数信息保存到 servicemetadata#attachments 中
servicemetadata.getAttachments().putAll(map);
// 注册消费者
ServiceRepository repository = ApplicationModel.getServiceRepository();
ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
repository.registerConsumer(
servicemetadata.getServiceKey(),
attributes,
serviceDescriptor,
this,
null,
servicemetadata);
// 创建提供者代理类
ref = createProxy(map);
servicemetadata.setTarget(ref);
servicemetadata.addAttribute(PROXY_CLASS_REF, ref);
// 保存提供者代理类的引用关系
repository.lookupReferredService(servicemetadata.getServiceKey()).setProxyObject(ref);
initialized = true;
// dispatch a ReferenceConfigInitializedEvent since 2.7.4
// 分发 ReferenceConfigInitializedEvent 事件
dispatch(new ReferenceConfigInitializedEvent(this, invoker));
}
以上:内容部分参考
https://blog.csdn.net/weixin_38308374/article/details/105938319
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正



