1. 程式人生 > 實用技巧 >dubbo-config-spring自定義xml標籤擴充套件

dubbo-config-spring自定義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中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屬性;

  下面根據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();
    }
}