1. 要了解Dubbo是如何解析標簽的,首先要清楚一點就是Spring如何處理自定義標簽的,因為Dubbo的標簽可以算是Spring自定義標簽的一種情況;
2. Spring通過兩個接口來解析自定義的標簽:NamespaceHandler和BeanDefinitionParser接口;NamespaceHandler負責namespace的處理,而BeanDefinitionParser負責Bean的解析;
3. 我們自定義標簽的時候,可以實現NamespaceHandler接口,但更多的是繼承NamespaceHandler的抽象類:NamespaceHandlerSupport,然后在classpath的META-INF目錄下編寫一個spring.handlers文件,在該文件中定義namespace的URL和namespace處理類的映射。
比如Dubbo的spring.handlers文件內容(/是轉義):
http\://code.alibabatech.com/schema/dubbo=com.alibaba.dubbo.config.spring.schema.DubboNamespaceHandler
4. spring框架初始化時會加載所有classpath的spring.handlers文件,把namespace的URL和namespace處理類映射到Map中,Spring在解析的時候,遇到一些自定義的標簽的時候,會在這個Map中查找namespace處理類,使用這個使用這個自定義的處理類來進行標簽的解析工作;
5. 同樣,Dubbo框架的namespace的處理類是DubboNamespaceHandler,也是實現了NamespaceHandlerSupport接口來處理命名空間,然后在這個類的初始化的時候給所有標簽都注冊了各自的解析器;而Dubbo的解析類DubboBeanDefinitionParser同樣也是實現了BeanDefinitionParser接口;
DubboNamespaceHandler 源代碼如此下:
/** * DubboNamespaceHandler * * @author william.liangf * @export */ 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)); } }
可以看到,Dubbo有10個標簽,每個標簽會解析到對應的實體上,每個實體中的屬性對應標簽中的屬性,比如ApplicationConfig類:
/** * ApplicationConfig * * @author william.liangf * @export */ public class ApplicationConfig extends AbstractConfig { private static final long serialVersionUID = 5508512956753757169L; // 應用名稱 private String name; // 模塊版本 private String version; // 應用負責人 private String owner; // 組織名(BU或部門) private String organization; // 分層 private String architecture; // 環境,如:dev/test/run private String environment; // Java代碼編譯器 private String compiler; // 日志輸出方式 private String logger; // 注冊中心 private List<RegistryConfig> registries; // 服務監控 private MonitorConfig monitor; // 是否為缺省 private Boolean isDefault; public ApplicationConfig() { } public ApplicationConfig(String name) { setName(name); } @Parameter(key = Constants.APPLICATION_KEY, required = true) public String getName() { return name; } public void setName(String name) { checkName("name", name); this.name = name; if (id == null || id.length() == 0) { id = name; } } @Parameter(key = "application.version") public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getOwner() { return owner; } public void setOwner(String owner) { checkMultiName("owner", owner); this.owner = owner; } public String getOrganization() { return organization; } public void setOrganization(String organization) { checkName("organization", organization); this.organization = organization; } public String getArchitecture() { return architecture; } public void setArchitecture(String architecture) { checkName("architecture", architecture); this.architecture = architecture; } public String getEnvironment() { return environment; } public void setEnvironment(String environment) { checkName("environment", environment); if(environment != null) { if (! ("develop".equals(environment) || "test".equals(environment) || "product".equals(environment))) { throw new IllegalStateException("Unsupported environment: " + environment + ", only support develop/test/product, default is product."); } } this.environment = environment; } public RegistryConfig getRegistry() { return registries == null || registries.size() == 0 ? null : registries.get(0); } public void setRegistry(RegistryConfig registry) { List<RegistryConfig> registries = new ArrayList<RegistryConfig>(1); registries.add(registry); this.registries = registries; } public List<RegistryConfig> getRegistries() { return registries; } @SuppressWarnings({ "unchecked" }) public void setRegistries(List<? extends RegistryConfig> registries) { this.registries = (List<RegistryConfig>)registries; } public MonitorConfig getMonitor() { return monitor; } public void setMonitor(MonitorConfig monitor) { this.monitor = monitor; } public void setMonitor(String monitor) { this.monitor = new MonitorConfig(monitor); } public String getCompiler() { return compiler; } public void setCompiler(String compiler) { this.compiler = compiler; AdaptiveCompiler.setDefaultCompiler(compiler); } public String getLogger() { return logger; } public void setLogger(String logger) { this.logger = logger; LoggerFactory.setLoggerAdapter(logger); } public Boolean isDefault() { return isDefault; } public void setDefault(Boolean isDefault) { this.isDefault = isDefault; } }
Dubbo版本:2.8.4.5