如果要弄明白dubbo如何嵌入spring中,首先要弄明白:spring.xml中的<dubbo>節點,spring是如何識別并解析的;
spring支持第三方命名空間
spring的擴展性非常強大,支持自定義第三方命令空間(不是<bean>
的節點都是第三方命名空間,都要指定handler),具體實現方式為在META-INF/spring.handlers文件中以KV方式申明:第三方命名空間=處理類;例如添加對<aop>
的支持(在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,例如<bean>
節點;如果解釋dubbo-demo-provider.xml中<dubbo:service>
,那么由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中自定義的節點,例如<dubbo>,<aop>等;
spring解析xml中的<dubbo>
由于dubbo-config-spring模塊下的META-INF/spring.handlers
文件中定義了
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
所以spring.xml中<dubbo>
這樣的節點都由DubboNamespaceHandler進行解析;通過DubboNamespaceHandler源碼可知:<dubbo:service>
會被DubboBeanDefinitionParser轉換成ServiceBean對象,如果xml中定義了<dubbo:application name="dubbo-test" owner="afei"/>,則會被DubboBeanDefinitionParser轉換成ApplicationConfig對象:
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中的<dubbo>
節點,將相關屬性與其值封裝到RootBeanDefinition中;
RootBeanDefinition中的private volatile Object beanClass;就是具體對象,例如ApplicationConfig, RegistryConfig等;private MutablePropertyValues propertyValues;就是屬性&值的KV鍵值對;