dubbo-config-spring自定义xml标签扩展
Dubbo中的XML约束文件
实现自定义自定义标签扩展流程
要实现自定义自定义标签扩展,需要有如下步骤(在spring中定义了两个接口NamespaceHandler、BeanDefinitionParser,用来实现扩展)
1.设计配置属性和JavaBean,编写XSD文件;
2.NamespaceHandler注册一堆BeanDefinitionParser,利用它们来进行解析;
3.BeanDefinitionParser用于解析每个element的内容;
4.编写Spring.handlers和Spring.schemas文件以供Spring读取;Spring默认会加载jar包下的META-INF/spring.handlers文件寻找对应的NamespaceHandler;
Dubbo中的自定义标签实现
Dubbo中Spring扩展就是使用Spring的自定义类型,所以同样也有NamespaceHandler、BeanDefinitionParser;
org.apache.dubbo.config.spring.schema.DubboNamespaceHandler
org.apache.dubbo.config.spring.schema.DubboBeanDefinitionParser
org.apache.dubbo.config.spring.schema.DubboNamespaceHandler#init,该方法用于注册BeanDefinitionParser的实现类,DubboBeanDefinitionParser把不同的配置分别转化成Spring容器中的Bean对象(Config对象);
@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( "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());
}
对应的Bean,如下:
在Spring启动解析相应的配置标签时,相应的启动provider发布服务注册服务,而同时让consumer在启动的时候自动订阅发现服务,加入了两个Bean, ServiceBean、ReferenceBean,分别继承ServiceConfig和ReferenceConfig;同时还分别实现了InitializingBean、DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware接口;
-
InitializingBean
为Bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是实现该接口的类,在初始化Bean的时候会执行该方法;
-
DisposableBean
Bean被销毁的时候,spring容器会自动执行destory方法,比如释放资源
- ApplicationContextAware
实现了这个接口的Bean,当Spring容器初始化的时候,会自动的将ApplicationContext注入进来;
- ApplicationListener
ApplicationEvent事件监听,Spring容器启动后会发一个事件通知;
- BeanNameAware
获得自身初始化时,本身的Bean的id属性;
仿写自定义xml标签扩展
下面根据Spring提供接口仿写一个自定义xml标签扩展;
BeanDefinitionParser: 用于标签解析;
查看代码
/**
* 用于标签解析
*/
public class BeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return CommonBean. class ;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String id = element.getAttribute( "id" );
String beanName = element.getAttribute( "beanName" );
String createTime = element.getAttribute( "createTime" );
if (StringUtils.hasText(id)) {
builder.addPropertyValue( "id" , id);
}
if (StringUtils.hasText(beanName)) {
builder.addPropertyValue( "beanName" , beanName);
}
if (StringUtils.hasText(createTime)) {
builder.addPropertyValue( "createTime" , createTime);
}
}
}
BeanNamespaceHandler:调用标签解析处理
查看代码
/**
* 调用标签解析处理
*/
public class BeanNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
// 将节点名与解析类映射,当节点名称为bean,使用BeanDefinitionParser进行解析
registerBeanDefinitionParser( "bean" , new BeanDefinitionParser());
}
}
自定义标签配置,需要在META-INF下创建两个默认Spring配置文件来提供支持,一个是spring.schemas,另一个是spring.handlers,前者是为了验证自定义的xml配置文件是否符合要求,后者是定义Spring解析的配置文件;
spring.handlers
查看代码
http\: //org .example /schemas/bean =com.example.bean.schema.BeanNamespaceHandler
spring.schemas
查看代码
http\: //org .example /schemas/bean .xsd=META-INF /bean .xsd
定义一个与自定义配置标签相对应的JavaBean,可根据需要是否实现InitializingBean,ApplicationContextAware等接口;
查看代码
public class CommonBean implements InitializingBean, ApplicationContextAware {
protected String id;
protected String beanName;
protected String createTime;
private transient ApplicationContext applicationContext;
public String getId() {
return id;
}
public void setId(String id) {
this .id = id;
}
public String getBeanName() {
return beanName;
}
public void setBeanName(String beanName) {
this .beanName = beanName;
}
public String getCreateTime() {
return createTime;
}
public void setCreateTime(String createTime) {
this .createTime = createTime;
}
@Override
public void afterPropertiesSet() {
System.out.println(applicationContext.getBeansOfType( this .getClass()));
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this .applicationContext = applicationContext;
}
@Override
public String toString() {
return "CommonBean{" +
"id='" + id + '\ '' +
", beanName='" + beanName + '\ '' +
", creteTime='" + createTime + '\ '' +
'}' ;
}
}
创建一个工程进行测试
在resources目录下创建bean.xml;
查看代码
<beans xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xmlns:customer= "http://org.example/schemas/bean"
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: //org .example /schemas/bean http: //org .example /schemas/bean .xsd">
<customer:bean id = "user" beanName= "test1" createTime= "2020-08-12" />
< /beans >
测试类
查看代码
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "bean.xml" );
context.start();
}
}