dubbo(官网地址)是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,是阿里巴巴SOA服务化治理方案的核心框架。目前,阿里巴巴内部已经不再使用dubbo,但对很对未到一定量级的公司来说,dubbo依然是一个很好的选择。
之前在使用duubo的时候,对dubbo有了一些初步的了解,但没有深入,有些问题还是不清楚。所以准备静下心来看下dubbo源码。这里假设你对dubbo有一定的了解,不再详细的讲解dubbo的架构。如果没接触过dubbo,可以先从其官网了解。
dubbo号称通过spring的方式可以透明化接入应用,对应用没有任何api侵入。下面看看官方的consumer demo,其配置如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" />
<bean class="com.alibaba.dubbo.demo.consumer.DemoAction" init-method="start">
<property name="demoService" ref="demoService" />
</bean>
</beans>
另外还提供了一份properties文件:
dubbo.container=log4j,spring
dubbo.application.name=demo-consumer
dubbo.application.owner=
dubbo.registry.address=multicast://224.5.6.7:1234
应用中的调用:
package com.alibaba.dubbo.demo.consumer;
import com.alibaba.dubbo.demo.DemoService;
public class DemoAction {
private DemoService demoService;
public void setDemoService(DemoService demoService) {
this.demoService = demoService;
}
<pre name="code" class="java"> public void start() throws Exception {
String hello = demoService.sayHello("who are you");
System.out.println(hello);
}
}
可以看到,代码方面确实是零侵入,而在配置方面,则是增加了一些服务的声明,环境配置之类的(不可缺少)。对于开发者来说非常友好。那么dubbo是如何做到这点的呢。 这个demoService在consumer端明明没有具体的实现,为何能够正常的调用并获取到结果? 要了解原因,必须先了解spring开发的一个接口:FactoryBean。
spring中有两种bean,一种是普通的bean,一种是工厂bean,即FactoryBean。普通bean通过class字符串代表的类直接实例化对象,而工厂bean则是通过class字符串代表的工厂类的getObject()方法来实例化对象。如以下FactoryBean在spring中返回的是MyObject对象,而不是MyFactoryBean对象。 这里不过多介绍FactoryBean,有兴趣的同学可以自行google。
class MyFactoryBean implements FactoryBean<Object> {
public Object getObject() throws Exception {
return new MyObject();
}
........
}
了解了FactoryBean后,仍然有困惑。在上面的配置里,并没有出现FactoryBean的实现类。这里需要了解另外一个spring的知识点:schema扩展。在dubbo中,所有namespace=dubbo的标签将被dubbo自己解析, 具体见com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler。其中reference对应的类为com.alibaba.dubbo.config.spring.ReferenceBean,ReferenceBean是一个FactoryBean,通过getObject()来产生代理类,我们的故事也是从此类开始。
ReferenceBean继承自ReferenceConfig,并实现了FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean。
由于实现了InitializingBean,在初始化各个属性后会调用afterPropertiesSet, 实现比较简单,主要是对没有初始化的几个属性尝试用公共的默认配置进行初始化,这里就不再细讲:
public void afterPropertiesSet() throws Exception {
if (getConsumer() == null) {
// 如果没有配置consumer属性,则使用默认的consumer属性
}
if (getApplication() == null
&& (getConsumer() == null || getConsumer().getApplication() == null)) {
// 如果没有配置application则使用默认的application
}
if (getModule() == null
&& (getConsumer() == null || getConsumer().getModule() == null)) {
// 如果没有配置module则使用默认的module
}
if ((getRegistries() == null || getRegistries().size() == 0)
&& (getConsumer() == null || getConsumer().getRegistries() == null || getConsumer().getRegistries().size() == 0)
&& (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().size() == 0)) {
// 如果没有配置registries则使用默认的registries
}
if (getMonitor() == null
&& (getConsumer() == null || getConsumer().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
// 如果没有配置monitor则使用默认monitor
}
// 如果设置了init属性且为true,则初始化对象,默认是不初始化的
Boolean b = isInit();
if (b == null && getConsumer() != null) {
b = getConsumer().isInit();
}
if (b != null && b.booleanValue()) {
getObject();
}
}
由于实现了FactoryBean,当需要初始化或者应用中需要用到时,会调用getObject()方法获取实际的对象:
public Object getObject() throws Exception {
return get();
}
ge