如果要弄明白dubbo如何嵌入spring中,首先要弄明白:spring.xml中的
节点,spring是如何识别并解析的;
spring支持第三方命名空间
spring的扩展性非常强大,支持自定义第三方命令空间(不是
的节点都是第三方命名空间,都要指定handler),具体实现方式为在META-INF/spring.handlers文件中以KV方式申明:第三方命名空间=处理类;例如添加对
的支持(在spring-aop-3.2.16.RELEASE.jar包中META-INF/spring.handlers文件中有该定义,这里需要注意一点:http后的冒号":"前需要加转移符"\"):
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler;
spring如何解析第三方命名空间
spring解析spring.xml的源码在org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions()中,对应的源码如下:
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);
postProcessXml(root);
}
主要解析xml的业务逻辑在parseBeanDefinitions()
中,如果namespaceUri为"http://www.springframework.org/schema/beans",那么isDefaultNamespace()为true,例如
节点;如果解释dubbo-demo-provider.xml中
,那么由delegate.parseCustomElement(ele)处理。对应的源码如下:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
String namespaceUri = ele.getNamespaceURI();
if (delegate.isDefaultNamespace(namespaceUri)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
parseCustomElement(Element)的作用是根据namespaceUri得到NamespaceHandler,然后解释当前xml,主要步骤如下:
- 加载所有类路径下"META-INF/spring.handlers"文件中定义的handler集合得到Map;
- 根据namespaceUri得到其对应的NamespaceHandler,
- 用第2步得到的NamespaceHandler解析spring.xml中自定义的节点,例如
, 等;
spring解析xml中的
由于dubbo-config-spring模块下的META-INF/spring.handlers
文件中定义了
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
所以spring.xml中
这样的节点都由DubboNamespaceHandler进行解析;通过DubboNamespaceHandler源码可知:
会被DubboBeanDefinitionParser转换成ServiceBean对象,如果xml中定义了
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
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 DubboBeanDefinitionParser(AnnotationBean.class, true));
}
}
在DubboBeanDefinitionParser.parse()中解析spring.xml中的
节点,将相关属性与其值封装到RootBeanDefinition中;
RootBeanDefinition中的private volatile Object beanClass;就是具体对象,例如ApplicationConfig, RegistryConfig等;private MutablePropertyValues propertyValues;就是属性&值的KV键值对;