Loading

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();
    }
}

  

 

posted @ 2020-08-22 16:16  街头卖艺的肖邦  阅读(448)  评论(0编辑  收藏  举报