Dubbo提供了服務註冊、RPC服務調用、調用均衡、服務監控和服務failover等功能java
Dubbo框架中有兩個重要角色:(服務)提供者和(服務)消費者,這裏爲了簡單起見,將包含了dubbo提供者或消費者功能的應用模塊通稱爲dubbo客戶端。spring
如今大多數java應用都離不開Spring,因此其餘java解決方案,或多或少都會支持在Spring中使用,dubbo也不例外。在我記憶中,凡是想在Spring容器中發揮做用的框架,無非都是提供對應的Spring Bean來注入到Spring容器中,dubbo也同樣。在源代碼的dubbo-container-spring模塊中,惟一的類SpringContainer說明了這一點,它的start()方法直接經過ClassPathXmlApplicationContext來啓動Spring容器。有人立馬會問,SpringContainer的start()方法由誰調用?答案就是com.alibaba.dubbo.container.Main,它是dubbo的入口,Main類中的main方法將依次調用dubbo內置的Container的start()方法。若是沒有配置Spring xml文件的路徑,dubbo將會默認採用classpath*:META-INF/spring/*.xml。app
那麼問題來了,Spring是如何識別dubbo的那些自定義標籤的?Spring爲了支持用戶自定義類加載到Spring容器,提供了org.springframework.beans.factory.xml.NamespaceHandler接口和org.springframework.beans.factory.xml.NamespaceHandlerSupport抽象類,NamespaceHandler#init方法會在對象的構造函數調用以後、屬性初始化以前被DefaultNamespaceHandlerResolver調用。dubbo的DubboNamespaceHandler類正是繼承了NamespaceHandlerSupport,其代碼實現以下:框架
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)); } }
registerBeanDefinitionParser方法有父抽象了類NamespaceHandlerSupport的默認實現,第一個參數是elementName,即元素名稱,即告訴Spring你要解析哪一個標籤,第二個參數是BeanDefinitionParser的實現類,BeanDefinitionParser是Spring用來將xml元素轉換成BeanDefinition對象的接口。dubbo的DubboBeanDefinitionParser類就實現了這個接口,負責將標籤轉換成bean定義對象BeanDefinition。dubbo給其返回的BeanDefinition設置了下列屬性:ide
beanDefinition.setBeanClass(beanClass); 函數
beanDefinition.setLazyInit(false);spa
beanDefinition.getPropertyValues().addPropertyValue("id", id);xml
若是是dubbo:protocol標籤,dubboh還會檢查全部已經包含protocol屬性的BeanDefinition且protocol屬性對應的值是ProtocolConfig對象的bean,將其屬性的protocol值設置成當前的bean引用:對象
definition.getPropertyValues().addPropertyValue("protocol", new RuntimeBeanReference(id));blog
若是是dubbo服務提供者的dubbo:service標籤,則還會設置ref屬性爲對應接口class的實現類bean:
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
有沒有人想過,當使用dubbo服務提供者的dubbo:service標籤時,若是我既不設置id,也不設置name,則dubbo給它的ServiceBean在Spring容器中定義的ID是什麼? 答案就是:
if (generatedBeanName == null || generatedBeanName.length() == 0) { generatedBeanName = beanClass.getName(); } id = generatedBeanName; int counter = 2; while(parserContext.getRegistry().containsBeanDefinition(id)) { id = generatedBeanName + (counter ++); }
有人就會問,Spring怎麼知道你自定義了NamespaceHandlerSupport的實現類?Spring容器會默認加載classpath/META-INF下的spring.handlers和spring.schemas文件,來加載名空間處理器和xsd,因此dubbo-config-spring包下的META-INF目錄下就有這兩個文件。