文章目录
NamespaceHandlerSupport机制简介
spring允许框架开发者自定义xml标签完成beandefinition解析注册
其按照以下规范进行1 spring.handlers
2 spring.schemas 作用:在解析XML文件时将XSD重定向到本地文件,避免在解析XML文件时需要上网下载XSD文件
3 dubbo.xsd xml文件中,对用户xml程序进行编译校验
4 自定义 DubboNamespaceHandler,覆写init和parse方法工作机制:
1 DubboNamespaceHandler实现BeanDefinitionParser和自定义标签的绑定工作
2 在parse方法中根据xml标签寻找对应的BeanDefinitionParser完成解析
spring.handlers的作用就是使得spring容器能加载到相应的NamespaceHandler,从而完成非spring内置元素的解析 ,比如dubbo:service等等
DubboNamespaceHandler完成dubbo自定义标签解析成beandefinition过程
- 除去annotation[在xml中开启注解功能],所有标签都是DubboBeanDefinitionParser完成解析
- DubboBeanDefinitionParser指定了每一种xml标签的默认beanclass
- dubbo:service 默认的beanclass是ServiceBean
public class DubboNamespaceHandler extends NamespaceHandlerSupport implements ConfigurableSourceBeanMetadataElement{
@Override
public void init() {
<dubbo:application/>标签的解析器 应用
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
<dubbo:registry/>标签的解析器 注册中心 zk redis等等
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));
<dubbo:provider/>标签的解析器 标签的解析器提供者的一些共用属性
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
<dubbo:consumer/>标签的解析器 消费者的一些共用属性
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
<dubbo:protocol/>标签的解析器 协议标签:dubbo rest grpc等等远程通信协议
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
<dubbo:service/> 提供者
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
<dubbo:reference/>标签的解析器 消费者
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
}
构建Beandefinition
- 通过每一个标签对应的beanclass 构建beandefinition
- 根据xml构建PropertyValue
public class DubboBeanDefinitionParser implements BeanDefinitionParser {
public DubboBeanDefinitionParser(Class<?> beanClass, boolean required) {
this.beanClass = beanClass;
this.required = required;
}
完成xml到beandefinition的解析
主要设置了beanclass为内置的bean 比如服务提供者标签的ServiceBean.class
处理了PropertyValues将来用于依赖注入
@SuppressWarnings("unchecked")
private static RootBeanDefinition parse(Element element, ParserContext parserContext, Class<?> beanClass, boolean required) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
String id = resolveAttribute(element, "id", parserContext);
...... 删除id生成策略 一般情况我们beandefinition的beanname 就是包名+接口名组合
...... 删除其他标签处理代码
处理 <dubbo:protocol/>
if (ProtocolConfig.class.equals(beanClass)) {
...... 删除dubbo:protocol
} else if (ServiceBean.class.equals(beanClass)) {
根据class 解析ref
<dubbo:service id="sa" interface="com.alibaba.dubbo.demo.DemoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl"> 无需设置ref
String className = resolveAttribute(element, "class", parserContext);
...... 一般我们
if (StringUtils.isNotEmpty(className)) {
RootBeanDefinition classDefinition = new RootBeanDefinition();
classDefinition.setBeanClass(ReflectUtils.forName(className));
classDefinition.setLazyInit(false);
通过这种方式,可以使用 <property /> 标签,设置 Service Bean 的属性。
parseProperties(element.getChildNodes(), classDefinition, parserContext);
根据class 解析ref
beanDefinition.getPropertyValues().addPropertyValue("ref", new BeanDefinitionHolder(classDefinition, id + "Impl"));
}
}
...... 删除其他
创建已解析的属性集合
ManagedMap parameters = null;
...... 删除parameters构建流程 主要就是解析xml
spring篇幅中我们提到过PropertyValues 将来在bean实例化的过程中会处理依赖注入
if (parameters != null) {
beanDefinition.getPropertyValues().addPropertyValue("parameters", parameters);
}
return beanDefinition;
}
}
总结
- 基于xml的形式 我们知道spring容器中构建了大量的servicebean提供者,ReferenceBean消费者
- 没有显示提供,则这些接口的beanname为包名+接口名[一个service类既有dubbo注解也有spring注解,可以避免beanname相同]
- 以xml为例,这些servicebean被实例化注入spring容器之后,并没有完成服务暴露
- xml配置下,服务暴露的时机为spring refresh()调用finishRefresh,其会发布容器完成事件,DubboBootstrapApplicationListener会监听该事件,并完成服务暴露