Dubbo——架构和原理

一、架构设计图
Dubbo——架构和原理
1、service 业务逻辑层:接口和接口实现,dubbo的服务提供端暴露哪个接口和接口的实现,dubbo的服务消费端订阅的服务接口,用户仅需要关注这一层
2、config 配置层:对外配置接口,以 ServiceConfig、ReferenceConfig 为中心,可以直接初始化配置类(@Bean的方式),也可以通过 Spring 解析配置生成配置类
3、proxy 服务代理层:服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton,以 ServiceProxy 为中心,扩展接口为 ProxyFactory
4、registry 注册中心层:封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory,Registry,RegistryService
5、cluster 路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster、Directory、Router、LoadBalance
6、monitor 监控层:RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory、Monitor、MonitorService
7、protocol 远程调用层:封装 RPC 调用,以 Invocation、Result 为中心,扩展接口为 Protocol、Invoke、Exporter
8、exchange 信息交换层:封装请求响应模式,同步转异步,以 Request、Response 为中心,扩展接口为 Exchanger、ExchangeChannel、ExchangeClient、ExchangeServer
9、transport 网络传输层:抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel、Transporter、Client、Server、Codec
10、serialize 数据序列化层:可复用的一些工具,扩展接口为 Serialization、ObjectInput、ObjectOutput、ThreadPool

二、标签解析
Spring解析配置文件中的每一个标签都会有相应的类来完成,这些类都实现了同一个接口:BeanDefinitionParser

public abstract interface BeanDefinitionParser {
public abstract BeanDefinition parse(Element paramElement, ParserContext paramParserContext);
}

该接口的继承树如下:其中就有DubboBeanDefinitionParser用来解析配置文件中的dubbo标签
Dubbo——架构和原理
DubboBeanDefinitionParser的parse方法如下:可以看出来其实就是解析每一个标签的配置,并给相应的对象属性赋值

private static BeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass,
boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
String id = element.getAttribute("id");
if ((((id == null) || (id.length() == 0))) && (required)) {
String generatedBeanName = element.getAttribute("name");
if ((generatedBeanName == null) || (generatedBeanName.length() == 0)) {
if (ProtocolConfig.class.equals(beanClass))
generatedBeanName = "dubbo";
else {
generatedBeanName = element.getAttribute("interface");
}
}
if ((generatedBeanName == null) || (generatedBeanName.length() == 0)) {
generatedBeanName = beanClass.getName();
}
id = generatedBeanName;
int counter = 2;
while (parserContext.getRegistry().containsBeanDefinition(id)) {
id = generatedBeanName + (counter++);
}
}
if ((id != null) && (id.length() > 0)) {
if (parserContext.getRegistry().containsBeanDefinition(id)) {
throw new IllegalStateException("Duplicate spring bean id " + id);
}
parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);
beanDefinition.getPropertyValues().addPropertyValue("id", id);
}
if (ProtocolConfig.class.equals(beanClass)) {
for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {
BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);
PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol");
if (property != null) {
Object value = property.getValue();
if ((value instanceof ProtocolConfig) && (id.equals(((ProtocolConfig) value).getName())))
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));
}
}
} else if (ServiceBean.class.equals(beanClass)) {
String className = element.getAttribute("class");
if ((className != null) && (className.length() > 0)) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setLazyInit(false);
parseProperties(element.getChildNodes(), classDefinition);
beanDefinition.getPropertyValues().addPropertyValue("ref",
new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
} else if (ProviderConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ServiceBean.class, true, "service", "provider", id, beanDefinition);
} else if (ConsumerConfig.class.equals(beanClass)) {
parseNested(element, parserContext, ReferenceBean.class, false, "reference", "consumer", id,
beanDefinition);
}
Set props = new HashSet();
ManagedMap parameters = null;
for (Method setter : beanClass.getMethods()) {
String name = setter.getName();
if ((name.length() <= 3) || (!(name.startsWith("set"))) || (!(Modifier.isPublic(setter.getModifiers())))
|| (setter.getParameterTypes().length != 1)) {
continue;
}
Class type = setter.getParameterTypes()[0];
String property = StringUtils.camelToSplitName(name.substring(3, 4).toLowerCase() + name.substring(4), "-");
props.add(property);
Method getter = null;
try {
getter = beanClass.getMethod("get" + name.substring(3), new Class[0]);
} catch (NoSuchMethodException e) {
try {
getter = beanClass.getMethod("is" + name.substring(3), new Class[0]);
} catch (NoSuchMethodException localNoSuchMethodException1) {
}
}
if ((getter == null) || (!(Modifier.isPublic(getter.getModifiers()))))
continue;
if (!(type.equals(getter.getReturnType()))) {
continue;
}

if ("parameters".equals(property)) {
parameters = parseParameters(element.getChildNodes(), beanDefinition);
} else if ("methods".equals(property)) {
parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);
} else if ("arguments".equals(property)) {
parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);
} else {
String value = element.getAttribute(property);
if (value != null) {
value = value.trim();
if (value.length() > 0) {
if (("registry".equals(property)) && ("N/A".equalsIgnoreCase(value))) {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("N/A");
beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig);
} else if (("registry".equals(property)) && (value.indexOf(44) != -1)) {
parseMultiRef("registries", value, beanDefinition, parserContext);
} else if (("provider".equals(property)) && (value.indexOf(44) != -1)) {
parseMultiRef("providers", value, beanDefinition, parserContext);
} else if (("protocol".equals(property)) && (value.indexOf(44) != -1)) {
parseMultiRef("protocols", value, beanDefinition, parserContext);
} else {
Object reference;
Object reference;
if (isPrimitive(type)) {
if ((("async".equals(property)) && ("false".equals(value)))
|| (("timeout".equals(property)) && ("0".equals(value)))
|| (("delay".equals(property)) && ("0".equals(value)))
|| (("version".equals(property)) && ("0.0.0".equals(value)))
|| (("stat".equals(property)) && ("-1".equals(value)))
|| (("reliable".equals(property)) && ("false".equals(value)))) {
value = null;
}
reference = value;
} else {
Object reference;
if (("protocol".equals(property))
&& (ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value))
&& (((!(parserContext.getRegistry().containsBeanDefinition(value)))
|| (!(ProtocolConfig.class.getName().equals(parserContext.getRegistry()
.getBeanDefinition(value).getBeanClassName())))))) {
if ("dubbo:provider".equals(element.getTagName())) {
logger.warn("Recommended replace <dubbo:provider protocol=\"" + value
+ "\" ... /> to <dubbo:protocol name=\"" + value + "\" ... />");
}

ProtocolConfig protocol = new ProtocolConfig();
protocol.setName(value);
reference = protocol;
} else if ("onreturn".equals(property)) {
int index = value.lastIndexOf(".");
String returnRef = value.substring(0, index);
String returnMethod = value.substring(index + 1);
Object reference = new RuntimeBeanReference(returnRef);
beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod", returnMethod);
} else if ("onthrow".equals(property)) {
int index = value.lastIndexOf(".");
String throwRef = value.substring(0, index);
String throwMethod = value.substring(index + 1);
Object reference = new RuntimeBeanReference(throwRef);
beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod", throwMethod);
} else if ("oninvoke".equals(property)) {
int index = value.lastIndexOf(".");
String invokeRef = value.substring(0, index);
String invokeRefMethod = value.substring(index + 1);
Object reference = new RuntimeBeanReference(invokeRef);
beanDefinition.getPropertyValues().addPropertyValue("oninvokeMethod",
invokeRefMethod);
} else {
if (("ref".equals(property))
&& (parserContext.getRegistry().containsBeanDefinition(value))) {
BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);
if (!(refBean.isSingleton())) {
throw new IllegalStateException("The exported service ref " + value
+ " must be singleton! Please set the " + value
+ " bean scope to singleton, eg: <bean id=\"" + value
+ "\" scope=\"singleton\" ...>");
}
}
reference = new RuntimeBeanReference(value);
}
}
beanDefinition.getPropertyValues().addPropertyValue(property, reference);
}
}
}
}
}

NamedNodeMap attributes = element.getAttributes();
int len = attributes.getLength();
for (int i = 0; i < len; ++i) {
Node node = attributes.item(i);
String name = node.getLocalName();
if (!(props.contains(name))) {
if (parameters