dubbo的consumer的初始过程
一个常见的consumer配置是这样的
<dubbo:reference id="dubboDemo" interface="com.company.dsp.adcenter.protocol.dubbo.DubboDemo"
protocol="dubbo"/>
这样spring会创建一个beanName为dubboDemo的bean,使用上是这样的
@Resource(name = "dubboDemo")
private DubboDemo dubboDemo;
那么问题来了why why why? dubbo是怎么创建这样的bean的?全程都没有要求我们使用bean标签,也没有要求使用Componment和Service注解,即使使用显示的方式声明一个Bean,那我们也没有相关的实现类啊。
既然我们已经拥有上面的配置项,拍脑袋一想,已知dubbo启动时会利用spring对自定义配置项的spring.handles文件加载对应的handler解析自定义节点,且上文书已经分析
dubbo:reference节点的配置项存储在com.alibaba.dubbo.config.spring.ReferenceBean
中,该类的uml图如下。
可见该类集成自com.alibaba.dubbo.config.ReferenceConfig
类,并实现了下面四个接口
org.springframework.beans.factory.FactoryBean
org.springframework.context.ApplicationContextAware
org.springframework.beans.factory.InitializingBean
org.springframework.beans.factory.DisposableBean
InitializingBean和ApplicationContextAware我们都很熟悉了,还没详细了解过FactoryBean,不过这里有一个道友的文章可以看看《FactoryBean的实现原理与作用》
其中提到了以下两句
OK,那么这个时候我们getBean(“personFactory”)得到的就是Person对象而不是PersonFactoryBean对象。具体原理参考上面在IOC的应用,我们通过bean = getObjectForBeanInstance(sharedInstance, name, beanName, null)这个方法,具体调用到了getObject方法,所以结果很明显。
通过上面的小案例的代码,我们可以看到如果一个类实现了FactoryBean接口,那么getBean得到的不是他本身了,而是它所产生的对象,如果我们希望得到它本身,只需要加上&符号即可。至于FactoryBean的实际应用,需要大家去发现理解,后面如果有机会会继续聊聊这个东西。
那把目光转向:com.alibaba.dubbo.config.spring.ReferenceBean
,开启找寻getObject方法之旅
/**
* ReferenceFactoryBean
*
* @author william.liangf
* @export
*/
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
//......
public Object getObject() throws Exception {
return get();
}
//......
}
其中get()方法 继承自com.alibaba.dubbo.config.ReferenceConfig
public synchronized T get() {
if (destroyed){
throw new IllegalStateException("Already destroyed!");
}
if (ref == null) {
init();
}
return ref;
}
可见get方法内部调用了一个init()方法
private void init() {
if (initialized) {
return;
}
initialized = true; //初始化标记,防止重复创建对象
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
}
// 获取消费者全局配置,检查consumer是否有配置,如果该属性为null,则new一个ConsumerConfig对象
// 方法内部调用appendProperties(consumer)方法,该方法内部会拼装一个 dubbo.tagName.属性名的key,在配置文件中查找值,如果有值则调用属性的setter方法,设置属性值。
checkDefault();
// 上边注释已经说明appendProperties方法用途
appendProperties(this);
if (getGeneric() == null && getConsumer() != null) { //判断是不是泛化调用
setGeneric(getConsumer().getGeneric());
}
if (ProtocolUtils.isGeneric(getGeneric())) {
interfaceClass = GenericService.class;
} else {
try {
interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
//继承自com.alibaba.dubbo.config.AbstractInterfaceConfig
//检查接口类中是否存在指定的方法,如果dubbo:service->dubbo:method 没有配置的情况下,methods为null,该方法不会执行方法校验。
//如果有相关的配置,该方法会检查name属性对应的方法是否存在,不存在会抛IllegalStateException异常。
checkInterfaceAndMethods(interfaceClass, methods);
}
//用-Ddubbo.resolve.file指定映射文件路径,此配置优先级高于<dubbo:reference>中的配置,1.0.15及以上版本支持
//......省略-Ddubbo.resolve.file的解析代码行......//
//........省略进一步初始化相关配置的代码行 .......//
//检查应用配置,如果没有配置会创建默认对象。其内部会调用appendProperties(AbstractConfig config) 填充属性。
//检查失败会抛出IllegalStateException异常
checkApplication();
//
c