ok!经过前面几篇的讲解,我们已经知晓了如下几个知识点:
- Spring自定义Xml标签的解析
- Dubbo xml标签解析的入口
- Dubbo是如何解析xml配置的
- Dubbo最后把解析的配置放到哪了。
既然配置已经解析完毕,那么下一步盲猜就是根据配置来发布服务了(针对provider来说)。那我们这篇就来谈谈Dubbo的服务发布,当然,肯定会分篇聊的。下面我们开始吧!
说明
从该篇起,我们就开始去着手分析Dubbo服务的发布和注册功能的实现了,该部分要涉及到的代码很多,而且也很绕。
你会在里面经常看到之前我们说过的SPI扩展类,所以有时候会晕,于是我会分几篇进行说明,每篇说一点,并且会对该篇的内容画个时序图,当然,时序图可能画的并不那么专业,但是总比没有的好(自我安慰~)。
这篇就是起个头,估计不会分析到真正核心的部分。
下面就让我们进入正题吧。
ServiceBean
还记得下面这张图么?

我们之前说过,里面有几个特殊的地方,也就是config-center
、service
、reference
这几个标签在创建Parser的时候,第一个参数和其他的不同,其他都是xxxxConfig
,只有这几个是xxxBean
。我们今天先看看service
标签所对应的ServiceBean
。
InitializingBean.afterPropertiesSet()
InitializingBean我们知道它是Spring的一个接口,里面只有一个afterPropertiesSet()
方法,我们的类只要是实现了该接口,就必须得重写这个方法。
那么有什么用呢?Spring在我们xml解析之后,就会拿到所有实现了InitializingBean
接口的bean,然后调用其afterPropertiesSet()
方法。
也就是说,这个afterPropertiesSet()
是在xml配置解析完成后调用。回到Dubbo,我们上一篇刚说完它的配置解析,那么我们可以想一下,既然配置解析完了,按照逻辑下一步是不是把服务初始化好,然后暴露出去,注册到zk或者其他注册中心上。
那么按照这个逻辑,然后dubbo又是依赖Spring的,然后刚好发现在ServiceBean
上有实现这个接口,那么我们就尝试着下个断点,让它跑起来,看看是否可以断下。然后我们再继续往下分析。

看,断下来了,然后我们翻翻这个方法,发现在最后有如下代码:
1 2 3 4
| if (!supportedApplicationListener) { export(); }
|
看到export()
,我们盲猜字面意识就是导出,导出什么呢?在这里只能是导出我们的服务了。也就是说afterPropertiesSet()
方法在经过一系列操作后,最终会导出我们的服务,那么这一系列操作做了啥事呢?这就是该篇要分析的内容。
代码一共有200行左右,所以我们拆分下,分为几步去分析。把代码的if折叠下,刚好可以分为如下几部分

让我们一步一步的分析下去。
第一个if条件——设置Provider属性(已过时)
我们以这个if条件为例,剖析里面的实现,虽然Provider已经废弃,平常我们都是用<dubbo:service>
来声明服务,但丝毫不影响我们通过这块代码来深入。后续的if体内都是差不多,所以有了这个基础,我们看后面的就很容易。
第一部分
1 2 3 4
| if (getProvider() == null) { Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false); }
|
这里的getProvider()
方法得到的是一个ProviderConfig
对象,这里说如果是null,就会进我们的if体,那可以盲猜一下,在这个if体里肯定是为这个ProviderConfig
赋值,具体是不是,我们还得往下分析去验证。
在这个if体里面,我们暂时只抠出了一行代码,这一行代码得拆分一下看。也就是如下这样:
- 先判断applicationContext是不是为null,如果为null,直接把Map赋值为null。
- 如果不为null,就会调
BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false)
,把得到的返回值赋给providerConfigMap
。
那么这里有两个问题。
applicationContext
是什么时候赋值的,在哪里赋值的。
BeanFactoryUtils.beansOfTypeIncludingAncestors()
是什么?有什么用?
第一个问题
我们先看看第一个问题,applicationContext
是什么时候赋值的。我们碰到这个问题,第一反应是找applicationContext
的调用,看看在哪用到了,发下在ServiceBean
中有如下代码:
1 2 3 4 5 6 7
| @Override public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; SpringExtensionFactory.addApplicationContext(applicationContext); supportedApplicationListener = addApplicationListener(applicationContext, this); }
|
我们可以看到,他是通过setApplicationContext()
方法为applicationContext
赋值的,然后细心的朋友已经发现在该方法上面有个@Override
的注解,一般这个注解我们是在重写方法的时候会加上,那么肯定是ServiceBean
有继承或者实现某个类或接口,这种情况才会发生重载,并且这里是Spring的applicationContext
,那我们可以找找,是否有某个接口里面有该方法。最后发现是在ApplicationContextAware
接口中有该方法。
这里就有一个知识点了,一般情况下,我们想拿到一个ApplicationContext
对象会怎么操作?手动new一个?但是这又不是main方法,如果再new一个,不就有多个ApplicationContext
了?所以这种直接new的方法是不可取的。那么怎么办呢?
Spring给我们提供了一种注入ApplicationContext
的途径,也就是实现这个ApplicationContextAware
接口,在Spring启动过后,就会调用其中的setApplicationContext()
方法,把ApplicationContext
对象传给我们。
那么第一个问题有答案了。下面来看第二个问题。
第二个问题
BeanFactoryUtils.beansOfTypeIncludingAncestors()
是什么?有什么用?我们直接看这个方法的源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public static <T> Map<String, T> beansOfTypeIncludingAncestors( ListableBeanFactory lbf, Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException {
Assert.notNull(lbf, "ListableBeanFactory must not be null"); Map<String, T> result = new LinkedHashMap<String, T>(4); result.putAll(lbf.getBeansOfType(type, includeNonSingletons, allowEagerInit)); if (lbf instanceof HierarchicalBeanFactory) { HierarchicalBeanFactory hbf = (HierarchicalBeanFactory) lbf; if (hbf.getParentBeanFactory() instanceof ListableBeanFactory) { Map<String, T> parentResult = beansOfTypeIncludingAncestors( (ListableBeanFactory) hbf.getParentBeanFactory(), type, includeNonSingletons, allowEagerInit); for (Map.Entry<String, T> entry : parentResult.entrySet()) { String beanName = entry.getKey(); if (!result.containsKey(beanName) && !hbf.containsLocalBean(beanName)) { result.put(beanName, entry.getValue()); } } } } return result; }
|
这里我们采取调试的方法,来看看确定下下面几个地方的值。
lbf
参数是什么类型,因为下面会调用它的getBeansOfType()
方法。
getBeansOfType()
方法具体是调用谁的,内部实现是怎么样的。
断点断下来后,这两个的值分别如下:
第二部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| if (providerConfigMap != null && providerConfigMap.size() > 0) { Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); if (CollectionUtils.isEmptyMap(protocolConfigMap) && providerConfigMap.size() > 1) { List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>(); for (ProviderConfig config : providerConfigMap.values()) { if (config.isDefault() != null && config.isDefault()) { providerConfigs.add(config); } } if (!providerConfigs.isEmpty()) { setProviders(providerConfigs); } } else { ProviderConfig providerConfig = null; for (ProviderConfig config : providerConfigMap.values()) { if (config.isDefault() == null || config.isDefault()) { if (providerConfig != null) { throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config); } providerConfig = config; } } if (providerConfig != null) { setProvider(providerConfig); } } }
|
以上代码,唯一要单独说的就是setProviders()
和setProvider()
方法。该方法在ServiceBean
的父类ServiceConfig
中,这个关联关系我们之前已经说过了。两个方法分别代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @Deprecated public void setProviders(List<ProviderConfig> providers) { this.protocols = convertProviderToProtocol(providers); }
@Deprecated private static List<ProtocolConfig> convertProviderToProtocol(List<ProviderConfig> providers) { if (CollectionUtils.isEmpty(providers)) { return null; } List<ProtocolConfig> protocols = new ArrayList<ProtocolConfig>(providers.size()); for (ProviderConfig provider : providers) { protocols.add(convertProviderToProtocol(provider)); } return protocols; } @Deprecated
private static ProtocolConfig convertProviderToProtocol(ProviderConfig provider) { ProtocolConfig protocol = new ProtocolConfig(); protocol.setName(provider.getProtocol().getName()); protocol.setServer(provider.getServer()); protocol.setClient(provider.getClient()); protocol.setCodec(provider.getCodec()); protocol.setHost(provider.getHost()); protocol.setPort(provider.getPort()); protocol.setPath(provider.getPath()); protocol.setPayload(provider.getPayload()); protocol.setThreads(provider.getThreads()); protocol.setParameters(provider.getParameters()); return protocol; }
public void setProvider(ProviderConfig provider) { ConfigManager.getInstance().addProvider(provider); this.provider = provider; }
|
那么,这两个部分的代码合起来,无非就是做了如下几件事:
- 从Spring容器中获取所有
ProviderConfig
类的对象,结果是一个Map。key是bean的名字,value就是bean对象。
- 如果ProviderConfigMap不为空,则获取所有
ProtocolConfig
类的对象。
- 如果有配多协议(
ProtocolConfig
对象不止一个),就把所有的ProviderConfig
对象加入到List,并且调用setProviders()
方法为ServiceConfig
里面的protocols
属性赋值。在内部,会把ProviderConfig
转为ProtocolConfig
- 如果没有配置多协议呢,就直接赋值给
ServiceConfig
里面的provider
属性,如果有多个,就会报错。
注意,上面的都已经过时,在新版本中不推荐这样用了。这里是为了兼容旧版本
第二个if条件——设置ApplicationConfig
有了一个if条件的经验,我们就直接来看代码吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| if (getApplication() == null && (getProvider() == null || getProvider().getApplication() == null)) { Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, false, false); if (applicationConfigMap != null && applicationConfigMap.size() > 0) { ApplicationConfig applicationConfig = null; for (ApplicationConfig config : applicationConfigMap.values()) { if (applicationConfig != null) { throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config); } applicationConfig = config; } if (applicationConfig != null) { setApplication(applicationConfig); } } }
|
这段代码毫无疑问,是从Spring中读取我们解析到的<dubbo:application>
所对应的ApplicationConfig
对象。然后保存到ServiceConfig
中。简单吧。后面的if体,我就稍微注释下,不会再像现在这样了。下面我们看第三个if。
第三个if条件——设置ModuleConfig
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| if (getModule() == null && (getProvider() == null || getProvider().getModule() == null)) { Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, false, false); if (moduleConfigMap != null && moduleConfigMap.size() > 0) { ModuleConfig moduleConfig = null; for (ModuleConfig config : moduleConfigMap.values()) { if (config.isDefault() == null || config.isDefault()) { if (moduleConfig != null) { throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config); } moduleConfig = config; } } if (moduleConfig != null) { setModule(moduleConfig); } } }
|
这段代码就不注释了,原因是因为和上面结构差不多,而且<dubbo:module>
这个配置很少用。
第四个if条件——设置RegistryIds
1 2 3 4 5 6 7 8 9 10
| if (StringUtils.isEmpty(getRegistryIds())) { if (getApplication() != null && StringUtils.isNotEmpty(getApplication().getRegistryIds())) { setRegistryIds(getApplication().getRegistryIds()); } if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getRegistryIds())) { setRegistryIds(getProvider().getRegistryIds()); } }
|
第五个if条件——设置注册中心配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| if ((CollectionUtils.isEmpty(getRegistries())) && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getRegistries())) && (getApplication() == null || CollectionUtils.isEmpty(getApplication().getRegistries()))) { Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, false, false); if (CollectionUtils.isNotEmptyMap(registryConfigMap)) { List<RegistryConfig> registryConfigs = new ArrayList<>(); if (StringUtils.isNotEmpty(registryIds)) { Arrays.stream(COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id -> { if (registryConfigMap.containsKey(id)) { registryConfigs.add(registryConfigMap.get(id)); } }); } if (registryConfigs.isEmpty()) { for (RegistryConfig config : registryConfigMap.values()) { if (StringUtils.isEmpty(registryIds)) { registryConfigs.add(config); } } } if (!registryConfigs.isEmpty()) { super.setRegistries(registryConfigs); } } }
|
第六个if条件——设置元数据配置(新特性)
1 2 3 4 5 6 7 8 9 10
| if (getMetadataReportConfig() == null) { Map<String, MetadataReportConfig> metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, false, false); if (metadataReportConfigMap != null && metadataReportConfigMap.size() == 1) { super.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next()); } else if (metadataReportConfigMap != null && metadataReportConfigMap.size() > 1) { throw new IllegalStateException("Multiple MetadataReport configs: " + metadataReportConfigMap); } }
|
第七个if条件——监控相关配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| if (getMonitor() == null && (getProvider() == null || getProvider().getMonitor() == null) && (getApplication() == null || getApplication().getMonitor() == null)) { Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, false, false); if (monitorConfigMap != null && monitorConfigMap.size() > 0) { MonitorConfig monitorConfig = null; for (MonitorConfig config : monitorConfigMap.values()) { if (config.isDefault() == null || config.isDefault()) { if (monitorConfig != null) { throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config); } monitorConfig = config; } } if (monitorConfig != null) { setMonitor(monitorConfig); } } }
|
第八个if条件——设置Metrics
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| if (getMetrics() == null) { Map<String, MetricsConfig> metricsConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class, false, false); if (metricsConfigMap != null && metricsConfigMap.size() > 0) { MetricsConfig metricsConfig = null; for (MetricsConfig config : metricsConfigMap.values()) { if (metricsConfig != null) { throw new IllegalStateException("Duplicate metrics configs: " + metricsConfig + " and " + config); } metricsConfig = config; } if (metricsConfig != null) { setMetrics(metricsConfig); } } }
|
第九个if条件——设置ProtocolIds
1 2 3 4 5
| if (StringUtils.isEmpty(getProtocolIds())) { if (getProvider() != null && StringUtils.isNotEmpty(getProvider().getProtocolIds())) { setProtocolIds(getProvider().getProtocolIds()); } }
|
第十个if条件——保存协议信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| if (CollectionUtils.isEmpty(getProtocols()) && (getProvider() == null || CollectionUtils.isEmpty(getProvider().getProtocols()))) { Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); if (protocolConfigMap != null && protocolConfigMap.size() > 0) { List<ProtocolConfig> protocolConfigs = new ArrayList<ProtocolConfig>(); if (StringUtils.isNotEmpty(getProtocolIds())) { Arrays.stream(COMMA_SPLIT_PATTERN.split(getProtocolIds())) .forEach(id -> { if (protocolConfigMap.containsKey(id)) { protocolConfigs.add(protocolConfigMap.get(id)); } }); } if (protocolConfigs.isEmpty()) { for (ProtocolConfig config : protocolConfigMap.values()) { if (StringUtils.isEmpty(protocolIds)) { protocolConfigs.add(config); } } } if (!protocolConfigs.isEmpty()) { super.setProtocols(protocolConfigs); } } }
|
第十一个if条件——保存path
1 2 3 4 5 6 7 8
| if (StringUtils.isEmpty(getPath())) { if (StringUtils.isNotEmpty(beanName) && StringUtils.isNotEmpty(getInterface()) && beanName.startsWith(getInterface())) { setPath(beanName); } }
|
最后一个if——导出
1 2 3 4
| if (!supportedApplicationListener) { export(); }
|
总结
这一篇有点不尽人意。总体意识很简单,就是从Spring容器中把我们上一篇解析的出来的配置,保存到ServiceConfig
中,后面我们开始真正进入服务导出的内容了,我们一起期待。
对了,那我们<dubbo:service>
标签的配置是怎么放到ServiceConfig
中的呢?在上一篇中,我们是直接把配置就已经解析好了的,也就是说ServiceBean
中在执行afterPropertiesSet()
方法前,就已经把<dubbo:service>
的配置保存了,而这里只是保存下其他的标签的配置到ServiceBean
,说白点就是为ServiceBean
的一些需要的属性赋值,以便后续导出服务时使用。
这篇可能写的不怎么好,没得状态。谢谢大佬们的观看,下一篇再见~