本文基于 Dubbo 2.6.1 版本,望知悉。
友情提示,【配置 】这块的内容,会相对比较枯燥。所以,如果看到一些很难懂的地方,建议先跳过。
对于 Dubbo ,重点是要去理解,多协议、RPC、容错等等模块,而不是【配置 】。
😈 估计好多胖友被【配置 】这章劝退了把???
1. 概述 在 Dubbo 提供的几种方式中,XML 配置 肯定是大家最熟悉的方式。
如果胖友不熟悉,可以查看如下文档:
XML 配置,自定义 <dubbo: />
标签,基于 Spring XML 进行解析。如果不了解的胖友,可以查看如下文档:
2. 定义 2.1 sprng.schemas Dubbo 在 dubbo-spring-config
的 META-INF/spring.schemas
定义如下:
http\://code.alibabatech.com/schema/dubbo/dubbo.xsd=META-INF/dubbo.xsd
xmlns
为 http://code.alibabatech.com/schema/dubbo
xsd
为 META-INF/dubbo.xsd
2.2 dubbo.xsd dubbo.xsd
定义如下:
dubbo.xsd
<xsd:element name="" />
,定义了元素的名称 。例如,<xsd:element name="application" />
对应 <dubbo:application />
。
<xsd:element type="" />
,定义了内建数据类型的名称 。例如,<xsd:element type="applicationType" />
对应 <xsd:complexType name="applicationType" />
。
<xsd:complexType name="">
,定义了复杂类型 。例如 <xsd:complexType name="applicationType" />
如下:
applicationType
2.3 spring.handlers spring.handlers
定义如下:
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
定义了 Dubbo 的 XML Namespace 的处理器 DubboNamespaceHandler 。
2.4 DubboNamespaceHandler com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
,实现 org.springframework.beans.factory.xml.NamespaceHandlerSupport
抽象类 ,Dubbo 的 XML Namespace 的处理器。
在 #init()
方法,定义了每个 <xsd:element />
对应的 org.springframework.beans.factory.xml.BeanDefinitionParser
,代码如下:
@Override 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()); }
细心的胖友,会看到 service
标签使用的是 ServiceBean ,而不是 ServiceConfig ,reference
表示用的是 ReferenceBean ,因为无论是 ServiceConfig 还是 ReferenceBean ,在解析完具体配置后,需要调用它们对应的方法进行初始化 。🙂 考虑到篇幅,我们在后续文章分享。这篇我们重点放在解析 。
3. 解析 com.alibaba.dubbo.config.spring.schema.DubboBeanDefinitionParser
,实现 org.springframework.beans.factory.xml.BeanDefinitionParser
接口 ,Dubbo Bean 定义解析器。
3.1 构造方法 构造方法 ,代码如下:
private final Class<?> beanClass;private final boolean required;public DubboBeanDefinitionParser (Class<?> beanClass, boolean required) { this .beanClass = beanClass; this .required = required; }
beanClass
,Bean 对象的类 。
required
,是否需要在 Bean 对象的编号( id
) 不存在时,自动生成编号 。无需被其他应用引用的配置对象,无需自动生成编号。例如有 <dubbo:reference />
。
3.2 解析方法【主流程】 #parse(Element, ParserContext)
方法,解析 XML 元素。代码如下:
public BeanDefinition parse (Element element, ParserContext parserContext) { return parse(element, parserContext, beanClass, required); }
友情提示:建议胖友,能够边看边调试。
3.2.1 创建 RootBeanDefinition #parse(Element, ParserContext, beanClass, required)
的第 78 至 80 行,代码如下:
RootBeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClass(beanClass); beanDefinition.setLazyInit(false );
默认 lazyInit = false
。
FROM 《Dubbo 用户指南 —— XML 配置》 引用缺省是延迟初始化的,只有引用被注入到其它 Bean,或被 getBean() 获取,才会初始化。如果需要饥饿加载,即没有人引用也立即生成动态代理,可以配置:<dubbo:reference ... init="true" />
3.2.2 处理 Bean 的编号 #parse(Element, ParserContext, beanClass, required)
的第 81 至 111 行,代码如下:
81 : 82 : String id = element.getAttribute("id" ); 83 : if ((id == null || id.length() == 0 ) && required) { 84 : 85 : String generatedBeanName = element.getAttribute("name" ); 86 : if (generatedBeanName == null || generatedBeanName.length() == 0 ) { 87 : if (ProtocolConfig.class.equals(beanClass)) { 88 : generatedBeanName = "dubbo" ; 89 : } else { 90 : generatedBeanName = element.getAttribute("interface" ); 91 : } 92 : } 93 : if (generatedBeanName == null || generatedBeanName.length() == 0 ) { 94 : generatedBeanName = beanClass.getName(); 95 : } 96 : id = generatedBeanName; 97 : 98 : int counter = 2 ; 99 : while (parserContext.getRegistry().containsBeanDefinition(id)) { 100 : id = generatedBeanName + (counter++);101 : }102 : }103 : if (id != null && id.length() > 0 ) {104 : if (parserContext.getRegistry().containsBeanDefinition(id)) {105 : throw new IllegalStateException("Duplicate spring bean id " + id);106 : }107 : 108 : parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);109 : 110 : beanDefinition.getPropertyValues().addPropertyValue("id" , id);111 : }
第 82 至 102 行:解析 Bean 的 id
。若不存在,则自动进行生成。
第 85 至 96 行:生成 id
。规则为 name
> 特殊规则 > className
。
第 97 至 101 行:若 id
在 Spring 注册表已经存在,通过添加自增序列 作为后缀,避免冲突。
第 108 行:添加 Bean 到 Spring 注册表。
第 110 行:设置 Bean 的 id
。
3.2.3 处理 <dubbo:protocol/>
特殊情况 #parse(Element, ParserContext, beanClass, required)
的第 113 至 128 行,代码如下:
113 : 114 : if (ProtocolConfig.class.equals(beanClass)) {115 : 116 : 117 : 118 : 119 : for (String name : parserContext.getRegistry().getBeanDefinitionNames()) {120 : BeanDefinition definition = parserContext.getRegistry().getBeanDefinition(name);121 : PropertyValue property = definition.getPropertyValues().getPropertyValue("protocol" );122 : if (property != null ) {123 : Object value = property.getValue();124 : if (value instanceof ProtocolConfig && id.equals(((ProtocolConfig) value).getName())) {125 : definition.getPropertyValues().addPropertyValue("protocol" , new RuntimeBeanReference(id));126 : }127 : }128 : }
在 「3.2.7 循环 Bean 对象的 setting 方法,将属性赋值到 Bean 对象」 统一解析。
3.2.4 处理 <dubbo:service />
的 class
属性 #parse(Element, ParserContext, beanClass, required)
的第 129 至 142 行,代码如下:
113 : 114 : } else if (ServiceBean.class.equals(beanClass)) {115 : 116 : String className = element.getAttribute("class" );117 : if (className != null && className.length() > 0 ) {118 : 119 : RootBeanDefinition classDefinition = new RootBeanDefinition();120 : classDefinition.setBeanClass(ReflectUtils.forName(className));121 : classDefinition.setLazyInit(false );122 : 123 : parseProperties(element.getChildNodes(), classDefinition);124 : 125 : beanDefinition.getPropertyValues().addPropertyValue("ref" , new BeanDefinitionHolder(classDefinition, id + "Impl" ));126 : }
3.2.5 解析 <dubbo:provider />
的内嵌子元素 <dubbo:service />
#parse(Element, ParserContext, beanClass, required)
的第 143 至 145 行,代码如下:
} else if (ProviderConfig.class.equals(beanClass)) { parseNested(element, parserContext, ServiceBean.class, true , "service" , "provider" , id, beanDefinition);
3.2.6 解析 <dubbo:consumer />
的内嵌子元素 <dubbo:reference />
#parse(Element, ParserContext, beanClass, required)
的第 146 至 149 行,代码如下:
} else if (ConsumerConfig.class.equals(beanClass)) { parseNested(element, parserContext, ReferenceBean.class, false , "reference" , "consumer" , id, beanDefinition); }
3.2.7 循环 Bean 对象的 setting 方法,将属性赋值到 Bean 对象 #parse(Element, ParserContext, beanClass, required)
的第 150 至 273 行,代码如下:
150 : Set<String> props = new HashSet<String>(); 151 : ManagedMap parameters = null ; 152 : 153 : for (Method setter : beanClass.getMethods()) {154 : String name = setter.getName();155 : if (name.length() > 3 && name.startsWith("set" )156 : && Modifier.isPublic(setter.getModifiers())157 : && setter.getParameterTypes().length == 1 ) { 158 : Class<?> type = setter.getParameterTypes()[0 ];159 : 160 : String property = StringUtils.camelToSplitName(name.substring(3 , 4 ).toLowerCase() + name.substring(4 ), "-" );161 : props.add(property);162 : 163 : Method getter = null ;164 : try {165 : getter = beanClass.getMethod("get" + name.substring(3 ), new Class<?>[0 ]);166 : } catch (NoSuchMethodException e) {167 : try {168 : getter = beanClass.getMethod("is" + name.substring(3 ), new Class<?>[0 ]);169 : } catch (NoSuchMethodException e2) {170 : }171 : }172 : if (getter == null 173 : || !Modifier.isPublic(getter.getModifiers())174 : || !type.equals(getter.getReturnType())) {175 : continue ;176 : }177 : 178 : if ("parameters" .equals(property)) {179 : parameters = parseParameters(element.getChildNodes(), beanDefinition);180 : 181 : } else if ("methods" .equals(property)) {182 : parseMethods(id, element.getChildNodes(), beanDefinition, parserContext);183 : 184 : } else if ("arguments" .equals(property)) {185 : parseArguments(id, element.getChildNodes(), beanDefinition, parserContext);186 : } else {187 : String value = element.getAttribute(property);188 : if (value != null ) {189 : value = value.trim();190 : if (value.length() > 0 ) {191 : 192 : if ("registry" .equals(property) && RegistryConfig.NO_AVAILABLE.equalsIgnoreCase(value)) {193 : RegistryConfig registryConfig = new RegistryConfig();194 : registryConfig.setAddress(RegistryConfig.NO_AVAILABLE);195 : beanDefinition.getPropertyValues().addPropertyValue(property, registryConfig);196 : 197 : } else if ("registry" .equals(property) && value.indexOf(',' ) != -1 ) {198 : parseMultiRef("registries" , value, beanDefinition, parserContext);199 : 200 : } else if ("provider" .equals(property) && value.indexOf(',' ) != -1 ) {201 : parseMultiRef("providers" , value, beanDefinition, parserContext);202 : 203 : } else if ("protocol" .equals(property) && value.indexOf(',' ) != -1 ) {204 : parseMultiRef("protocols" , value, beanDefinition, parserContext);205 : } else {206 : Object reference;207 : 208 : if (isPrimitive(type)) {209 : 210 : if ("async" .equals(property) && "false" .equals(value)211 : || "timeout" .equals(property) && "0" .equals(value)212 : || "delay" .equals(property) && "0" .equals(value)213 : || "version" .equals(property) && "0.0.0" .equals(value)214 : || "stat" .equals(property) && "-1" .equals(value)215 : || "reliable" .equals(property) && "false" .equals(value)) {216 : 217 : value = null ;218 : }219 : reference = value;220 : 221 : } else if ("protocol" .equals(property)222 : && ExtensionLoader.getExtensionLoader(Protocol.class).hasExtension(value) 223 : && (!parserContext.getRegistry().containsBeanDefinition(value) 224 : || !ProtocolConfig.class.getName().equals(parserContext.getRegistry().getBeanDefinition(value).getBeanClassName())) 225 : ) {226 : 227 : if ("dubbo:provider" .equals(element.getTagName())) {228 : logger.warn("Recommended replace <dubbo:provider protocol=\"" + value + "\" ... /> to <dubbo:protocol name=\"" + value + "\" ... />" );229 : }230 : 231 : ProtocolConfig protocol = new ProtocolConfig();232 : protocol.setName(value);233 : reference = protocol;234 : 235 : } else if ("onreturn" .equals(property)) {236 : 237 : int index = value.lastIndexOf("." );238 : String returnRef = value.substring(0 , index);239 : String returnMethod = value.substring(index + 1 );240 : 241 : reference = new RuntimeBeanReference(returnRef);242 : 243 : beanDefinition.getPropertyValues().addPropertyValue("onreturnMethod" , returnMethod);244 : 245 : } else if ("onthrow" .equals(property)) {246 : 247 : int index = value.lastIndexOf("." );248 : String throwRef = value.substring(0 , index);249 : String throwMethod = value.substring(index + 1 );250 : 251 : reference = new RuntimeBeanReference(throwRef);252 : 253 : beanDefinition.getPropertyValues().addPropertyValue("onthrowMethod" , throwMethod);254 : 255 : } else {256 : 257 : if ("ref" .equals(property) && parserContext.getRegistry().containsBeanDefinition(value)) {258 : BeanDefinition refBean = parserContext.getRegistry().getBeanDefinition(value);259 : if (!refBean.isSingleton()) {260 : 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\" ...>" );261 : }262 : }263 : 264 : reference = new RuntimeBeanReference(value);265 : }266 : 267 : beanDefinition.getPropertyValues().addPropertyValue(property, reference);268 : }269 : }270 : }271 : }272 : }273 : }
第 150 行:已解析的属性集合 props
。该属性在 「3.2.8 将 XML 元素未遍历到的属性,添加到 parameters
集合中」 会使用到。
第 151 行:解析的参数集合 parameters
。
第 153 行:循环 Bean 对象的 setting 方法,将属性添加到 Bean 对象的属性赋值。
第 154 至 157 行:判断方法符合 setting && public
&& 唯一参数的条件。
第 159 至 161 行:添加属性名 到 props
。
第 162 至 176 行:判断方法符合 getting && public
&& 返回类型与 setting 参数类型一致 的条件。
第 177 至 179 行:调用 #parseParameters(id, nodeList, beanDefinition, parserContext)
方法,解析 <dubbo:argument />
标签。详细解析见 「3.3.6 parseParameters」 方法。
第 180 至 182 行:调用 #parseMethods(id, nodeList, beanDefinition, parserContext)
方法,解析 <dubbo:method />
标签。详细解析见 「3.3.4 parseMethods」 方法。
第 183 至 185 行:调用 #parseArguments(id, nodeList, beanDefinition, parserContext)
方法,解析 <dubbo:argument />
标签。详细解析见 「3.3.5 parseArguments」 方法。
第 191 至 195 行:处理 "registry"
属性,不想注册到注册中心的情况,即 registry=N/A
。
第 196 至 204 行:调用 #parseMultiRef(property, beanDefinition, parserContext)
方法,处理多注册中心、多服务提供者、多协议的情况下。详细解析见 「3.3. parseMultiRef」 方法。
第 207 至 219 行:处理属性类型为基础属性 ( #isPrimitive(Class<?>)
)的情况。
第 220 至 233 行:这块比较复杂 。"protocol"
属性,在多个标签中会使用,例如 <dubbo:service />
或者 <dubbo:provider />
等等。根据 《Dubbo 文档 —— schema 配置参考手册》 的说明,"protocol"
代表的是指向的 <dubbo:protocol />
的编号( id
)。
【此处是猜测】但是,早期的版本,"protocol"
属性,代表的是协议名 。这就麻烦了,和现有的逻辑有冲突啊!
那怎么解决呢?优先以指向的 <dubbo:protocol />
的编号 ( id
) 为准备,否则认为是协议名 。
那实际在解析 Bean 对象时,带有 "protocol"
属性的标签,无法保证一定在 <dubbo:protocol />
之后 解析。那咋整呢?
如果带有 "protocol"
属性的标签先 解析,先【第 221 至 223 行】直接 创建 ProtocolConfig 对象并设置到 "protocol"
属性,再【第 119 至 127 行】在 <dubbo:protocol />
解析后,进行覆盖 。这样,如果不存在 <dubbo:protocol />
的情况,最多不进行覆盖呢。
如果带有 "protocol"
属性的标签后 解析,无需走上述流程,走【第 257 至 264 行】即可。
🙂 如果这段无法理解,可以给我留言,有点绕。
第 234 至 243 行 || 第 244 至 253 行:处理 "onreturn"
和 "onthrow"
属性。该属性用于 《Dubbo 用户指南 —— 事件通知》 功能。
第 254 至 264 行:剩余情况,通用解析,创建 RuntimeBeanReference 对象。例如,<dubbo:service />
的 "ref"
属性。
第 267 行:设置 Bean 的属性值。该属性值来自第 206 至 265 行代码的逻辑 。
3.2.8 将 XML 元素未遍历到的属性,添加到 parameters
集合中 #parse(Element, ParserContext, beanClass, required)
的第 274 至 290 行,代码如下:
274 : 275 : NamedNodeMap attributes = element.getAttributes();276 : int len = attributes.getLength();277 : for (int i = 0 ; i < len; i++) {278 : Node node = attributes.item(i);279 : String name = node.getLocalName();280 : if (!props.contains(name)) {281 : if (parameters == null ) {282 : parameters = new ManagedMap();283 : }284 : String value = node.getNodeValue();285 : parameters.put(name, new TypedStringValue(value, String.class));286 : }287 : }288 : if (parameters != null ) {289 : beanDefinition.getPropertyValues().addPropertyValue("parameters" , parameters);290 : }
第 275 至 287 行:将 XML 元素,未在上面遍历到的属性 ,添加到 parameters
集合中。目前测试下来,不存在这样的情况。
第 288 至 290 行:设置 Bean 的 parameters
。
3.3 解析方法【辅流程】 3.3.1 parseProperties #parseProperties(NodeList, RootBeanDefinition)
方法,解析 Service Bean 对象的属性们。代码如下:
1 : 7 : private static void parseProperties (NodeList nodeList, RootBeanDefinition beanDefinition) { 8 : if (nodeList != null && nodeList.getLength() > 0 ) { 9 : for (int i = 0 ; i < nodeList.getLength(); i++) { 10 : Node node = nodeList.item(i);11 : if (node instanceof Element) {12 : if ("property" .equals(node.getNodeName())13 : || "property" .equals(node.getLocalName())) {14 : String name = ((Element) node).getAttribute("name" );15 : if (name != null && name.length() > 0 ) {16 : String value = ((Element) node).getAttribute("value" );17 : String ref = ((Element) node).getAttribute("ref" );18 : 19 : if (value != null && value.length() > 0 ) {20 : beanDefinition.getPropertyValues().addPropertyValue(name, value);21 : 22 : } else if (ref != null && ref.length() > 0 ) {23 : beanDefinition.getPropertyValues().addPropertyValue(name, new RuntimeBeanReference(ref));24 : } else {25 : throw new UnsupportedOperationException("Unsupported <property name=\"" + name + "\"> sub tag, Only supported <property name=\"" + name + "\" ref=\"...\" /> or <property name=\"" + name + "\" value=\"...\" />" );26 : }27 : }28 : }29 : }30 : }31 : }32 : }
第 11 至 13 行:只 解析 <property />
标签。
第 18 至 20 行:优先使用 "value"
属性。
第 21 至 23 行:其次使用 "ref"
属性。
第 24 至 27 行:属性补全,抛出异常。
3.3.2 parseNested #parseNested(...)
方法,解析内嵌的指向的子 XML 元素。代码如下:
1 : 13 : private static void parseNested (Element element, ParserContext parserContext, Class<?> beanClass, boolean required, String tag, 14 : String property, String ref, BeanDefinition beanDefinition) {15 : NodeList nodeList = element.getChildNodes();16 : if (nodeList != null && nodeList.getLength() > 0 ) {17 : boolean first = true ;18 : for (int i = 0 ; i < nodeList.getLength(); i++) {19 : Node node = nodeList.item(i);20 : if (node instanceof Element) {21 : if (tag.equals(node.getNodeName())22 : || tag.equals(node.getLocalName())) { 23 : 24 : if (first) {25 : first = false ;26 : String isDefault = element.getAttribute("default" );27 : if (isDefault == null || isDefault.length() == 0 ) {28 : beanDefinition.getPropertyValues().addPropertyValue("default" , "false" );29 : }30 : }31 : 32 : BeanDefinition subDefinition = parse((Element) node, parserContext, beanClass, required);33 : 34 : if (subDefinition != null && ref != null && ref.length() > 0 ) {35 : subDefinition.getPropertyValues().addPropertyValue(property, new RuntimeBeanReference(ref));36 : }37 : }38 : }39 : }40 : }41 : }
第 20 至 22 行:只 解析指定标签 。目前有内嵌 的 <dubbo:service />
和 <dubbo:reference />
标签。
第 32 行:解析指定标签,创建子 Bean 对象。
第 33 至 36 行:设置创建的子 Bean 对象,指向父 Bean 对象。
3.3.3 parseMultiRef #parseMultiRef(property, beanDefinition, parserContext)
方法,解析多指向的情况,例如多注册中心,多协议等等。代码如下:
1 : 9 : @SuppressWarnings ("unchecked" ) 10 : private static void parseMultiRef (String property, String value, RootBeanDefinition beanDefinition, 11 : ParserContext parserContext) {12 : String[] values = value.split("\\s*[,]+\\s*" );13 : ManagedList list = null ;14 : for (int i = 0 ; i < values.length; i++) {15 : String v = values[i];16 : if (v != null && v.length() > 0 ) {17 : if (list == null ) {18 : list = new ManagedList();19 : }20 : list.add(new RuntimeBeanReference(v));21 : }22 : }23 : beanDefinition.getPropertyValues().addPropertyValue(property, list);24 : }
第 12 至 22 行:以 .
拆分值 字符串,创建 RuntimeBeanReference 数组。
第 23 行:设置 Bean 对象的指定属性值。
3.3.4 parseMethods #parseMethods(id, nodeList, beanDefinition, parserContext)
方法,解析 <dubbo:method />
标签。代码如下:
1 : 9 : @SuppressWarnings ("unchecked" ) 10 : private static void parseMethods (String id, NodeList nodeList, RootBeanDefinition beanDefinition, 11 : ParserContext parserContext) {12 : if (nodeList != null && nodeList.getLength() > 0 ) {13 : ManagedList methods = null ; 14 : for (int i = 0 ; i < nodeList.getLength(); i++) {15 : Node node = nodeList.item(i);16 : if (node instanceof Element) {17 : Element element = (Element) node;18 : if ("method" .equals(node.getNodeName())19 : || "method" .equals(node.getLocalName())) { 20 : 21 : String methodName = element.getAttribute("name" );22 : if (methodName == null || methodName.length() == 0 ) {23 : throw new IllegalStateException("<dubbo:method> name attribute == null" );24 : }25 : if (methods == null ) {26 : methods = new ManagedList();27 : }28 : 29 : BeanDefinition methodBeanDefinition = parse(((Element) node), parserContext, MethodConfig.class, false );30 : 31 : String name = id + "." + methodName;32 : BeanDefinitionHolder methodBeanDefinitionHolder = new BeanDefinitionHolder(methodBeanDefinition, name);33 : methods.add(methodBeanDefinitionHolder);34 : }35 : }36 : }37 : if (methods != null ) {38 : beanDefinition.getPropertyValues().addPropertyValue("methods" , methods);39 : }40 : }41 : }
第 13 行:解析的方法数组 methods
。
第 16 至 19 行:只 解析 <dubbo:method>
标签。
第 29 行:调用 #parse(Element, ParserContext)
方法,主流程 ,解析 <dubbo:method>
标签,创建子 Bean 对象。
第 33 至 36 行:设置创建的子 Bean 对象,指向父 Bean 对象。
第 30 至 33 行:添加子 Bean 对象到 methods
中。
第 37 至 39 行:设置 Bean 的 methods
。
3.3.5 parseArguments #parseArguments(id, nodeList, beanDefinition, parserContext)
方法,解析 <dubbo:argument />
标签。
和 「3.3.4 parseMethods」 基本一致,🙂 胖友点击方法,直接查看代码。
3.3.6 parseParameters #parseParameters(id, nodeList, beanDefinition, parserContext)
方法,解析 <dubbo:argument />
标签。代码如下:
1 : 8 : @SuppressWarnings ("unchecked" ) 9 : private static ManagedMap parseParameters (NodeList nodeList, RootBeanDefinition beanDefinition) { 10 : if (nodeList != null && nodeList.getLength() > 0 ) {11 : ManagedMap parameters = null ;12 : for (int i = 0 ; i < nodeList.getLength(); i++) {13 : Node node = nodeList.item(i);14 : if (node instanceof Element) {15 : if ("parameter" .equals(node.getNodeName())16 : || "parameter" .equals(node.getLocalName())) { 17 : if (parameters == null ) {18 : parameters = new ManagedMap();19 : }20 : 21 : String key = ((Element) node).getAttribute("key" );22 : String value = ((Element) node).getAttribute("value" );23 : boolean hide = "true" .equals(((Element) node).getAttribute("hide" )); 24 : if (hide) {25 : key = Constants.HIDE_KEY_PREFIX + key;26 : }27 : parameters.put(key, new TypedStringValue(value, String.class));28 : }29 : }30 : }31 : return parameters;32 : }33 : return null ;34 : }
第 13 行:解析的参数集合 parameters
。
第 20 至 27 行:添加 "key"
"value"
到 parameters
。
666. 彩蛋 知识星球
稍显啰嗦的一篇文章,希望胖友能理解。
关于这块内容,在推荐下肥朝写的 《Dubbo源码解析 —— 简单原理、与 Spring 融合》 。