Dubbo——架构和原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rubulai/article/details/84996876

一、架构设计图
在这里插入图片描述
 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标签
在这里插入图片描述
  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 == null) {
				parameters = new ManagedMap();
			}
			String value = node.getNodeValue();
			parameters.put(name, new TypedStringValue(value, String.class));
		}
	}
	if (parameters != null) {
		beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
	}
	return beanDefinition;
}

  在标签的解析进入DubboBeanDefinitionParser的parse方法之前会先通过DubboNamespaceHandler的init初始化方法:在该方法中会先将所有的dubbo标签类型放在一个HashMap中(key为标签名,value为对应的标签解析对象),会将标签封装成对应的组件,这样在解析到这个标签时也就知道这个标签对应的是哪个类了。Spring的标签解析是逐个解析的,并不是在将配置文件一次性读完之后,一次性解析,而是读一个标签解析一个标签,因此dubbo的配置也可以参杂在Spring的bean配置文件中,效果是一样的,只不过单拉出来一个配置文件显得更规整

public class DubboNamespaceHandler extends NamespaceHandlerSupport {
	public void init() {
		registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
		registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
		registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
		registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
		registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
		registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
		registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
		registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
		registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
		registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
	}

	static {
		Version.checkDuplicate(DubboNamespaceHandler.class);
	}
}

  可以看到在解析到service和reference时并不是对应一个配置类(XxxConfig),而是一个Bean:

registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));

三、服务暴露流程
  在将标签封装为组件的时候,如果标签是service则会将该标签封装为ServiceBean,这个ServiceBean的源码如下:实现了InitializingBean和ApplicationListener两个接口,这两个接口的实现方法是afterPropertiesSet和onApplicationEvent

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean,
		ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {

	// ...

	public void onApplicationEvent(ContextRefreshedEvent event) {
		if ((isDelay()) && (!(isExported())) && (!(isUnexported()))) {
			if (logger.isInfoEnabled()) {
				logger.info("The service ready on spring started. service: " + getInterface());
			}
			export();
		}
	}

	//...

	public void afterPropertiesSet() throws Exception {
		if (getProvider() == null) {
			Map providerConfigMap = (this.applicationContext == null) ? null
					: BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProviderConfig.class,
							false, false);
			if ((providerConfigMap != null) && (providerConfigMap.size() > 0)) {
				Map protocolConfigMap = (this.applicationContext == null) ? null
						: BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProtocolConfig.class,
								false, false);
				if ((((protocolConfigMap == null) || (protocolConfigMap.size() == 0)))
						&& (providerConfigMap.size() > 1)) {
					List providerConfigs = new ArrayList();
					for (ProviderConfig config : providerConfigMap.values()) {
						if ((config.isDefault() != null) && (config.isDefault().booleanValue())) {
							providerConfigs.add(config);
						}
					}
					if (!(providerConfigs.isEmpty()))
						setProviders(providerConfigs);
				} else {
					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);
					}
				}
			}
		}
		if ((getApplication() == null) && (((getProvider() == null) || (getProvider().getApplication() == null)))) {
			Map applicationConfigMap = (this.applicationContext == null) ? null
					: BeanFactoryUtils.beansOfTypeIncludingAncestors(this.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);
				}
			}
		}
		if ((getModule() == null) && (((getProvider() == null) || (getProvider().getModule() == null)))) {
			Map moduleConfigMap = (this.applicationContext == null) ? null
					: BeanFactoryUtils.beansOfTypeIncludingAncestors(this.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().booleanValue())) {
						if (moduleConfig != null) {
							throw new IllegalStateException(
									"Duplicate module configs: " + moduleConfig + " and " + config);
						}
						moduleConfig = config;
					}
				}
				if (moduleConfig != null) {
					setModule(moduleConfig);
				}
			}
		}
		if ((((getRegistries() == null) || (getRegistries().isEmpty())))
				&& (((getProvider() == null) || (getProvider().getRegistries() == null)
						|| (getProvider().getRegistries().isEmpty())))
				&& (((getApplication() == null) || (getApplication().getRegistries() == null)
						|| (getApplication().getRegistries().isEmpty())))) {
			Map registryConfigMap = (this.applicationContext == null) ? null
					: BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, RegistryConfig.class,
							false, false);
			if ((registryConfigMap != null) && (registryConfigMap.size() > 0)) {
				List registryConfigs = new ArrayList();
				for (RegistryConfig config : registryConfigMap.values()) {
					if ((config.isDefault() == null) || (config.isDefault().booleanValue())) {
						registryConfigs.add(config);
					}
				}
				if ((registryConfigs != null) && (!(registryConfigs.isEmpty()))) {
					super.setRegistries(registryConfigs);
				}
			}
		}
		if ((getMonitor() == null) && (((getProvider() == null) || (getProvider().getMonitor() == null)))
				&& (((getApplication() == null) || (getApplication().getMonitor() == null)))) {
			Map monitorConfigMap = (this.applicationContext == null) ? null
					: BeanFactoryUtils.beansOfTypeIncludingAncestors(this.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().booleanValue())) {
						if (monitorConfig != null) {
							throw new IllegalStateException(
									"Duplicate monitor configs: " + monitorConfig + " and " + config);
						}
						monitorConfig = config;
					}
				}
				if (monitorConfig != null) {
					setMonitor(monitorConfig);
				}
			}
		}
		if ((((getProtocols() == null) || (getProtocols().isEmpty()))) && (((getProvider() == null)
				|| (getProvider().getProtocols() == null) || (getProvider().getProtocols().isEmpty())))) {
			Map protocolConfigMap = (this.applicationContext == null) ? null
					: BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ProtocolConfig.class,
							false, false);
			if ((protocolConfigMap != null) && (protocolConfigMap.size() > 0)) {
				List protocolConfigs = new ArrayList();
				for (ProtocolConfig config : protocolConfigMap.values()) {
					if ((config.isDefault() == null) || (config.isDefault().booleanValue())) {
						protocolConfigs.add(config);
					}
				}
				if ((protocolConfigs != null) && (!(protocolConfigs.isEmpty()))) {
					super.setProtocols(protocolConfigs);
				}
			}
		}
		if ((((getPath() == null) || (getPath().length() == 0))) && (this.beanName != null)
				&& (this.beanName.length() > 0) && (getInterface() != null) && (getInterface().length() > 0)
				&& (this.beanName.startsWith(getInterface()))) {
			setPath(this.beanName);
		}

		if (!(isDelay()))
			export();
	}
	
	//...
}

  在afterPropertiesSet()中会将标签中的配置信息保存起来,在onApplicationEvent()中调用export()暴露服务,具体的服务暴露流程参看下图:
在这里插入图片描述
四、服务引用流程
  此处说的服务引用是说在消费者端的Controller或者Service组件中通过@Autowired注入Dubbo的组件,我们知道在服务的消费者端是没有服务接口的实现的,那服务对象时怎么注入成功的呢,其实注入的是一个代理对象,原理如下:
  在将标签封装为组件的时候,如果标签是reference则会将该标签封装为ReferenceBean,这个ReferenceBean的源码如下:实现了FactoryBean接口,是一个工厂Bean

public class ReferenceBean<T> extends ReferenceConfig<T>
		implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
	private static final long serialVersionUID = 213195494150089726L;
	private transient ApplicationContext applicationContext;

	//...

	public Object getObject() throws Exception {
		return get();
	}

	public Class<?> getObjectType() {
		return getInterfaceClass();
	}

	@Parameter(excluded = true)
	public boolean isSingleton() {
		return true;
	}

	//...
}

  由于ReferenceBean实现了FactoryBean接口,因此在获取该Bean的实例时会调用getObject(),在该方法中会调用get(),之后会调用createProxy()创建代理,具体的服务引用流程如下图:
在这里插入图片描述
五、服务调用流程
在这里插入图片描述
 通过代理对象,在调用的过程中有容错、负载均衡、超时、失败重试等机制

猜你喜欢

转载自blog.csdn.net/rubulai/article/details/84996876