Dubbo服务暴露
1、Dubbo配置解析
1.1 配置解析
首先理解一个配置文件中元素的含义:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<dubbo:protocol name="dubbo"/>
<bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
<beams/>
- xmlns:dubbo : 声明前缀为dubbo的命名空间,后面的链接是赋予dubbo一个唯一的名字。他的值与xsi:schemaLocation中指定的第二个值http://dubbo.apache.org/schema/dubbo/dubbo.xsd相关,是里面的targetNamespace,如果他们的值不一致,编译会抛出异常
Caused by: org.xml.sax.SAXParseException; systemId: http://dubbo.apache.org/schema/dubbo/dubbo.xsd; lineNumber: 6; columnNumber: 68; TargetNamespace.1: 应为名称空间 'dubbo', 但方案文档的目标名称空间为 'http://dubbo.apache.org/schema/dubbo'。
除此之外,也需要与META-INF/下的spring.handler中的key相对应,指定当遇到这类命名空间时,Spring使用指定的Handler去加载该配置,如果不一致会抛出异常:
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://dubbo.apache.org/schema/dubbo]
- xmlns : 什么一个默认的命名空间,所有没有带前缀的元素,都会默认使用这个命名空间
- xsi:schemaLocation : 这个需要搭配命名空间使用。前面的http://dubbo.apache.org/schema/dubbo代表一个命名空间的名称,后面的http://dubbo.apache.org/schema/dubbo/dubbo.xsd代表供命名空间使用的XML schema的位置
- 对于里面的元素,比如<dubbo:protocol />则会使用到dubbo对应的xsd -> http://dubbo.apache.org/schema/dubbo/dubbo.xsd; 对应里面的protocol,具体的元素类型,对应里面的type属性指定的值。
1.1.1 基于schema设计解析
在Dubbo-config-spring下,有一个dubbo.xsd用于约束使用XML配置时的标签和对应的属性。Spring在解析到对应的一个命名空间的时候,会去spring.handlers和spring.schemas两个文件中,查找对应的一个Handler,用于解析对应的XML配置信息。例如
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
http\://code.alibabatech.com/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
当spring遇到http://dubbo.apache.org/schema/dubbo的时候,会使用DubboNamespaceHandler进行解析。
1.1.2 基于XML配置原理解析
从上面可知,XML的配置的约束的dubbo.xsd的作用,以及他的解析Handler。
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("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
registerBeanDefinitionParser("ssl", new DubboBeanDefinitionParser(SslConfig.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());
}
这一块主要是Spring的XML的解析逻辑,会将对应的一个element交给指定的一个Parser进行解析,会保存到一个map里面,以后遇到该element的时候,就使用对应的一个Parser进行解析。
解析的步骤
- 替换Id里面的占位符信息,得到一个ID
- 如果ID为空,则根绝名字生成ID,如果名字也为空,则使用类的名称
- 判断当前的容器中,是否存在一个相同的ID,存在的话,则抛出异常,不存在则注册该bean的信息
- 并设置propertyValue的值,添加ID信息
- 根据元素不同的类型,去解析不同的配置信息
- 找出xml中配置的所有的参数,并放入到beanDefinition中property中
1.1.3 基于注解配置原理解析
1.1.3.1 @EnableDubbo
EnableDubbo注解的作用是启用Dubbo的服务,当Spring在启动初始化的时候,会获取到对应配置头上的注解信息。在@EnableDubbo注解的头部,有两个注解比较重要@EnableDubboConfig和@DubboComponentScan。这两个注解中分别包含了一个@Import注解。
- @EnableDubboConfig
@Target({
ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
/**
* It indicates whether binding to multiple Spring Beans.
*
* @return the default value is <code>true</code>
* @revised 2.5.9
*/
boolean multiple() default true;
}
@Import注解中的值DubboConfigConfigurationRegistrar实现了ImportBeanDefinitionRegistrar,Spring容器在加载的时候会去加载@Import注解,并且执行其中值指定的类中的registerBeanDefinitions方法。
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
throws IOException {
if (visited.add(sourceClass)) {
for (SourceClass annotation : sourceClass.getAnnotations()) {
String annName = annotation.getMetadata().getClassName();
if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
collectImports(annotation, imports, visited);
}
}
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
对去递归的遍历所有的注解,如果注解的名称不是Import并且不是java开头的,则都会进行遍历。然后会去执行registerBeanDefinitions方法。
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
boolean multiple = attributes.getBoolean("multiple");
// Single Config Bindings
registerBeans(registry, DubboConfigConfiguration.Single.class);
// 配置的值是以dubbo.xxxs开头的,可以根据Multiple中的注解判断。其主要作用的是Multiple中的注解
if (multiple) {
// Since 2.6.6 https://github.com/apache/dubbo/issues/3193
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
// 将一些配置相关的Bean都注册到Spring容器中
// Since 2.7.6
registerCommonBeans(registry);
}
}
当设置为multiple的时候,例如dubbo.applations.name1.test1=test1Value会在加载ApplicationConfig的时候,name1会作为bean的名称,注入到容器中,test1/test1Value会作为keyValue的值,保存到BeanDefination中的attribute中。当有多个配置中心的时候,即可使用。
- @DubboComponentScan
Dubbo注解的扫描。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface