dubbo源码分析9——ServiceBean的afterPropertiesSet方法分析
ServiceBean的afterPropertiesSet方法是实现了InitializingBean,还是准备先做宏观分析,然后再做细致分析。下面先宏观分析:
public void afterPropertiesSet() throws Exception {
if (getProvider() == null) {
..............
//获取provider配置
}
if (getApplication() == null && (getProvider() == null || getProvider().getApplication() == null)) {
...............
//获取application配置
}
if (getModule() == null && (getProvider() == null || getProvider().getModule() == null)) {
...............
//获取module配置
}
if ((getRegistries() == null || getRegistries().size() == 0)
&& (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().size() == 0)
&& (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().size() == 0)) {
.................
//获取注册中心的配置
}
if (getMonitor() == null
&& (getProvider() == null || getProvider().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
................
//获取monitor配置
}
if ((getProtocols() == null || getProtocols().size() == 0)
&& (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().size() == 0)) {
...............
//获取protocol配置
}
if (getPath() == null || getPath().length() == 0) { //获取<dubbo:service/>的path属性,path即服务的发布路径
if (beanName != null && beanName.length() > 0
&& getInterface() != null && getInterface().length() > 0
&& beanName.startsWith(getInterface())) {
setPath(beanName); //如果没有设置path属性,则默认会以beanName作为path
}
}
if (! isDelay()) { //是否延迟暴露
export(); //进行服务暴露
}
}
通过上面的分析对整个方法在做什么有了大致的了解, 下面进行细致分析,对里面的一段段代码分别展开分析:
1 . 获取Provider配置
//当某个<dubbo:service/>没有绑定相应的<dubbo:provider/>的时候,就会触发下面的逻辑
if (getProvider() == null) {
//在spring的IOC容器中查找所有的type为ProviderConfig.class或其子类的bean,可能会有多个provider的配置
Map<String, ProviderConfig> providerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, false, false);
if (providerConfigMap != null && providerConfigMap.size() > 0) {
//在spring的IOC容器中查找type为ProtocolConfig.class或其子类的bean
Map<String, ProtocolConfig> protocolConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, false, false); //存在<dubbo:provider/>但不存在<dubbo:protocol/>配置的情况,也就是说旧版本的protocol配置需要从provider中提取
if ((protocolConfigMap == null || protocolConfigMap.size() == 0)&& providerConfigMap.size() > 1) { // 兼容旧版本
List<ProviderConfig> providerConfigs = new ArrayList<ProviderConfig>();
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() != null && config.isDefault().booleanValue()) {
providerConfigs.add(config); // 当<dubbo:provider default="true"/>时,providerConfigs才会加入
}
}
//在配置provider的同时,也从默认的<dubbo:provider/>中提取protocol的配置
if (providerConfigs.size() > 0) {
setProviders(providerConfigs);
}
} else { //已存在<dubbo:protocol/>配置,则找出默认的<dubbo:provider/>配置
ProviderConfig providerConfig = null;
for (ProviderConfig config : providerConfigMap.values()) {
if (config.isDefault() == null || config.isDefault().booleanValue()) {
if (providerConfig != null) {
throw new IllegalStateException("Duplicate provider configs: " + providerConfig + " and " + config);
}
providerConfig = config;
}
}
if (providerConfig != null) {
setProvider(providerConfig);
}
}
}
}
在这里补充一下什么是默认的<dubbo:provider/>,在dubbo配置文件中,可以有多个<dubbo:provider/>配置,如果某个<dubbo:provide/>配置的default属性为true。这个默认配置只能一个。
2.获取application配置
这个相对比较容易,只是说明几点,用户可以通过<dubbo:application/>的形式来配置application,也可以直接以bean的形式去配,这个bean对应的Class就是ApplicationConfig.class
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 (config.isDefault() == null || config.isDefault().booleanValue()) {
if (applicationConfig != null) {
throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
}
applicationConfig = config;
}
}
if (applicationConfig != null) {
setApplication(applicationConfig);
}
}
}
3. 获取Module,同上
4. 获取Registries,同上
5. 获取Monitor , 同上
6. 获取Protocols ,同上
7. 获取path(服务路径)
if (getPath() == null || getPath().length() == 0) {
if (beanName != null && beanName.length() > 0
&& getInterface() != null && getInterface().length() > 0
&& beanName.startsWith(getInterface())) {
setPath(beanName);
}
}
上面代码说明如果<dubbo:service/>没有配path属性,dubbo将会设置一个默认的path属性,默认值就是beanName,而beanName是ServiceBean实现了BeanNameAware接口,由spring的IOC容器传入进来的。通过上文对dubbo配置的解析的源码分析可知,一般情况这个path属性就是服务接口的类的全路径名。
8. 判断该服务是否延迟发布
if (! isDelay()) {
export(); //服务暴露的方法
}
<dubbo:service/>上会有一个delay的配置属性(官方的说明:)

private boolean isDelay() {
Integer delay = getDelay();
ProviderConfig provider = getProvider();
if (delay == null && provider != null) {
delay = provider.getDelay();
}
return supportedApplicationListener && (delay == null || delay.intValue() == -1);
}
上面为判断该服务是否延迟的方法的源码,说明如果<dubbo:service/>没有配delay属性或将其配置为-1都会延迟发布服务,而这个supportedApplicationListener属性在ServiceBean实现ApplicationContextAware接口的setApplicationContext方法中设置为true的。
下面再看一下setApplicationContext方法的源码,主要作用是为了兼容Spring2.0.1的版本,为了向前兼容spring的事件机制
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
SpringExtensionFactory.addApplicationContext(applicationContext);
if (applicationContext != null) {
SPRING_CONTEXT = applicationContext;
try {
Method method = applicationContext.getClass().getMethod("addApplicationListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
method.invoke(applicationContext, new Object[] {this});
supportedApplicationListener = true;
} catch (Throwable t) {
if (applicationContext instanceof AbstractApplicationContext) {
try {
Method method = AbstractApplicationContext.class.getDeclaredMethod("addListener", new Class<?>[]{ApplicationListener.class}); // 兼容Spring2.0.1
if (! method.isAccessible()) {
method.setAccessible(true);
}
method.invoke(applicationContext, new Object[] {this});
supportedApplicationListener = true;
} catch (Throwable t2) {
}
}
}
}
}
根据这个源码可知,通常我们的dubbo服务的配置:<dubbo:service interface="com.xxx.Yxxx" ref="userService" protocol="dubbo" retries="0" /> ,在这样的情况下 isDelay()方法返回true,所以我们的暴露将会发生在下面的方法中
public void onApplicationEvent(ApplicationEvent event) {
if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
if (isDelay() && ! isExported() && ! isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
}
至此,这个初始化的方法就分析完了。下文将开始分析 处理服务暴露的方法(export()方法)。
dubbo源码分析9——ServiceBean的afterPropertiesSet方法分析的更多相关文章
- dubbo源码分析4——SPI机制_ExtensionFactory类的作用
ExtensionFactory的源码: @SPI public interface ExtensionFactory { /** * Get extension. * * @param type o ...
- Dubbo源码学习--服务发布(ServiceBean、ServiceConfig)
前面讲过Dubbo SPI拓展机制,通过ExtensionLoader实现可插拔加载拓展,本节将接着分析Dubbo的服务发布过程. 以源码中dubbo-demo模块作为切入口一步步走进Dubbo源码. ...
- Dubbo 源码分析 - 服务导出
1.服务导出过程 本篇文章,我们来研究一下 Dubbo 导出服务的过程.Dubbo 服务导出过程始于 Spring 容器发布刷新事件,Dubbo 在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可 ...
- dubbo源码分析8——服务暴露概述
从上文中可知,com.alibaba.dubbo.config.spring.ServiceBean类是负责解析<dubbo:service/>的配置的,下面是它的类图 从类图上可知它继承 ...
- dubbo源码分析3-service bean的创建与发布
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- dubbo源码分析(一)-从xml到我们认识的Java对象
项目中用的dubbo的挺多的,然后随着自己对dubbo的慢慢深入,自己也希望能够了解dubbo的底层实现,这半年来一直在看dubbo的源码,有点断断续续的,于是准备写一个dubbo源码系列的分析文章, ...
- dubbo源码分析6-telnet方式的管理实现
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- dubbo源码分析1-reference bean创建
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- dubbo源码分析2-reference bean发起服务方法调用
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
随机推荐
- OS + RedHat 6.3 x64 NFS / mount.nfs: access denied by server while mounting
s Linux mount/unmount命令(转) https://www.cnblogs.com/xd502djj/p/3809375.html 问题2:NFS配置项no_root_squash和 ...
- Xenserver之设置Xenserver和VM机开机自动启动
一.设置Xenserver开机自动启动 [root@xenserver-DS-TestServer09 ~]# xe pool-list uuid ( RO) : b1c803a6-88cf-7b24 ...
- Python list 初始化技巧
1.一维列表 1.1 递增列表 # 初始化递增的list,与L = [i for i in range(10)] 效果相同 L = range(10) # 版本变化L = i for i in ran ...
- Linux下weblogic10.3.6(jar)版本安装详解
一.安装前的准备 安装weblogic是需要JDK环境的,虽然weblogic有自带的JDK,但是我一般是自己选择JDK进行安装,如果你要自行安装,可以参考我的另一篇博客 https://www.cn ...
- angular学习一框架结构认识
angular学习所有内容均会与vue以及react框架进行对比. angular学习使用的编译器:webstorm 解决编译器屏蔽node_modules包问题: File-->setting ...
- vs code配置git
在项目目录执行 git init 修改.git文件夹下的config文件 [core] repositoryformatversion = 0 filemode = false bare = fals ...
- Golang入门教程(十七)Linux/Windows下快速搭建和配置NSQ
前言 NSQ是一个基于Go语言的分布式实时消息平台,它基于MIT开源协议发布,代码托管在GitHub,其当前最新版本是0.3.1版.NSQ可用于大规模系统中的实时消息服务,并且每天能够处理数亿级别的消 ...
- Entity Framework 学习总结之十一:POCO
POCO Entity Framework 4.0 为实体提供了简单传统 CLR 对象( Plain Old CLR Object / POCO )支持.实体对象可以独立于 EF 存在,由此 EF 更 ...
- js监听键盘事件
用JS监听键盘按下事件(keydown event) 1.监听全局键盘按下事件,例如监听全局回车事件 1 $(document).keydown(function(event){ 2 if(eve ...
- 用IntelliJ IDEA搭建第一个SpringBoot例子
前言:最近把IntelliJ IDEA弄好了,也偶然接触到了springboot这个新的微服务框架.发现这个框架简单但也有一些不足.听说springboot可以在140个字符内发布一个web应用.所以 ...