1,配置信息node
先看看dubbo官方文檔給出的初始化過程:spring
基於 dubbo.jar 內的 META-INF/spring.handlers 配置,Spring 在遇到 dubbo 名稱空間時,會回調 DubboNamespaceHandler。 全部 dubbo 的標籤,都統一用 DubboBeanDefinitionParser 進行解析,基於一對一屬性映射,將 XML 標籤解析爲 Bean 對象。
找到dubbo.jar中的spring.handlers及DubboBeanDefinitionParser:apache
spring.handlers:markdown
http\://dubbo.apache.org/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
DubboBeanDefinitionParser:app
public class DubboNamespaceHandler extends NamespaceHandlerSupport { static { Version.checkDuplicate(DubboNamespaceHandler.class); } @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()); } }
上述registerBeanDefinitionParser註冊對應標籤的解釋器,即當遇到"application"(即<dubbo:application/>)時,使用
new DubboBeanDefinitionParser(ApplicationConfig.class, true)對其進行解析。ide
dubbo配置文件及其意義:this
一、xmlns="http://www.springframework.org/schema/beans" 聲明xml文件默認的命名空間,表示未使用其餘命名空間的全部標籤的默認命名空間。 二、xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 聲明XML Schema 實例,聲明後就可使用 schemaLocation 屬性 三、xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" 聲明前綴爲dubbo的命名空間,其唯一的做用是賦予命名空間一個唯一的名稱。當命名空間被定義在元素的開始標籤中時,全部帶有相同前綴的子元素都會與同一個命名空間相關聯。即當spring解析以dubbo開頭的標籤時,會把其命名空間設置爲"http://code.alibabatech.com/schema/dubbo",而這個命名空間名稱和spring.handlers中的一個key是相同的,這便是它們產生聯繫的地方。 四、xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd" 這個從命名能夠看出個大概,指定Schema的位置這個屬性必須結合命名空間使用。這個屬性有兩個值,第一個 值表示須要使用的命名空間。第二個值表示供命名空間使用的 XML schema 的位置。
2,源碼解析spa
配置文件解析發生在容器refresh的obtainFreshBeanFactory階段debug
調用棧:code
進到XmlBeanDefinitionReader#doLoadBeanDefinitions中:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { //將配置文件解析爲Document對象,其中級聯包含子節點,每一個子節點表明一個配置項 Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } .......... }
繼續往下走,來到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,這裏開始遍歷解析子節點:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { 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; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
因爲是自定義的配置,將會進入delegate.parseCustomElement(ele);
public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) { //獲取命名空間,若是是dubbo的配置,將會是"http://code.alibabatech.com/schema/dubbo" String namespaceUri = getNamespaceURI(ele); //更具命名空間,查找對應的Handler NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
進到DefaultNamespaceHandlerResolver#resolve:
public NamespaceHandler resolve(String namespaceUri) { //從jar包的META-INF/spring.handlers中讀取Handler信息 Map<String, Object> handlerMappings = getHandlerMappings(); Object handlerOrClassName = handlerMappings.get(namespaceUri); if (handlerOrClassName == null) { return null; } else if (handlerOrClassName instanceof NamespaceHandler) { return (NamespaceHandler) handlerOrClassName; } else { String className = (String) handlerOrClassName; try { Class<?> handlerClass = ClassUtils.forName(className, this.classLoader); if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) { throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface"); } //實例化Handler NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); //執行初始化方法,指定不一樣的標籤各自使用的解析器 namespaceHandler.init(); handlerMappings.put(namespaceUri, namespaceHandler); return namespaceHandler; } ....... } }
進到getHandlerMappings方法:
private Map<String, Object> getHandlerMappings() { if (this.handlerMappings == null) { synchronized (this) { if (this.handlerMappings == null) { try { Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); if (logger.isDebugEnabled()) { logger.debug("Loaded NamespaceHandler mappings: " + mappings); } Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size()); CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings); this.handlerMappings = handlerMappings; } } } } return this.handlerMappings; }
讀取文件的具體操做就不跟了,回到DefaultNamespaceHandlerResolver#resolve,看看獲取到的mapping:
其中一個則是以http://code.alibabatech.com/schema/dubbo 爲鍵, DubboNamespaceHandler爲值,所以,當解析dubbo的元素時,則會使用DubboNamespaceHandler
回到delegate.parseCustomElement,並進入到handler.parse中:
@Override public BeanDefinition parse(Element element, ParserContext parserContext) { return findParserForElement(element, parserContext).parse(element, parserContext); }
findParserForElement(element, parserContext),查找對應的解析器,即handler.init()中初始化的,而後對應解析器開始解析Element,最終在DubboBeanDefinitionParser#parse中進行構建RootBeanDefinition,並將構建好的RootBeanDefinition加入到容器中,並在容器refresh過程的finishBeanFactoryInitialization(beanFactory)中建立對應實例。