擴展spring schema文件

spring咱們在開發過程當中是個必不可少的框架,咱們一般會將咱們程序中的bean交由spring容器來進行管理,應用程序須要用到bean的時候從spring容器中去獲取,spring是如何實現這種方式的呢?spring的配置文件,當咱們在開發的過程當中發現spring提供的配置命令不知足的狀況下咱們該怎麼辦呢?咱們是否是要本身去解析原生的xml文件?固然不用spring爲開發者提供了可擴展的schema的支持,能夠支持自定義配置。spring

0x01 擴展配置步驟

  1. 在classpath的META-INF下定義另個文件:spring.handlers、spring.schemas(識別配置)app

  2. 自定義xsd文件(定義配置)框架

  3. 繼承org.springframework.beans.factory.xml.NamespaceHandlerSupport、org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser(解析配置)ide

0x02 識別配置

spring如何識別自定的schema文件ui

  1. spring.handlers指明命名空間須要哪一個類來處理。this

  2. spring.schemas指明瞭schema文件的位置,spring會使用這裏制定的xsd文件來驗證配置的正確性。spa

spring容器在啓動的時候會根據這兩個文件的配置加載文件內容,而後去解析文件中的配置信息。下面來看下具體的配置信息:code

spring.handlers文件的配置內容:orm

http\://code.liutxer.com/schema/bymq=com.liutxer.by.conf.RpcNamespaceHandler

http://code.liutxer.com/schem...這個命名空間使用com.liutxer.by.conf.RpcNamespaceHandler這個類來處理。xml

spring.schemas文件的配置內容:

http\://code.liutxer.com/schema/bymq/rpc.xsd=META-INF/rpc.xsd

http://code.liutxer.com/schem...文件的位置在classpath:/META-INF/rpc.xsd中

0x03 定義配置

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
        xmlns="http://code.liutxer.com/schema/bymq"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        targetNamespace="http://code.liutxer.com/schema/bymq"
        elementFormDefault="qualified"
        attributeFormDefault="unqualified">

    <xsd:import namespace="http://www.springframework.org/schema/beans" />

    <xsd:element name="service">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="interface" type="xsd:string" />
                    <xsd:attribute name="ref" type="xsd:string" />
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="reference">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="z" type="xsd:string" />
                    <xsd:attribute name="interface" type="xsd:string" />
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

其中要注意的點主要有xmlns--xml namespace、targetNamespace這兩個的定義。

0x04 解析配置

經過實現NamespaceHandlerSupport、BeanDefinitionParser完成對自定義的schema文件的解析工做。
NamespaceHandlerSupport會根據schema的節點名稱來找到某個BeanDefinitionParser而後由BeanDefinitionParser來完成具體的解析工做,所以咱們須要具體實現本身的NamespaceHandlerSupport和BeanDefinitionParser。下面看下具體實現:

public class RpcNamespaceHandler extends NamespaceHandlerSupport {

    public void init() {

        registerBeanDefinitionParser("service", new RpcBeanDefinitionParser(ServerBean.class));
        registerBeanDefinitionParser("reference", new RpcBeanDefinitionParser(ReferenceBean.class));
    }
}

上面實例主要說明service這個自定義標籤經過new RpcBeanDefinitionParser(ServerBean.class)經過這個parser進行解析。

public class RpcBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    private Class<?> beanClass;

    public RpcBeanDefinitionParser(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    protected Class getBeanClass(Element element) {
        return this.beanClass;
    }
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        if (ServerBean.class.equals(this.beanClass)) {

            String interfaceVal = element.getAttribute("interface");
            String refVal = element.getAttribute("ref");
            Object reference = new RuntimeBeanReference(refVal);

            if (StringUtils.hasText(interfaceVal)) {
                bean.addPropertyValue("interfaceVal", interfaceVal);
            }
            if (reference != null) {
                bean.addPropertyValue("ref", reference);
            }

        } else if (ReferenceBean.class.equals(this.beanClass)) {
            String beanName = element.getAttribute("id");
            String interfaceVal = element.getAttribute("interface");

            if (StringUtils.hasText(interfaceVal)) {
                bean.addPropertyValue("interfaceVal", interfaceVal);
            }
            if (StringUtils.hasText(beanName)) {
                bean.addPropertyValue("beanName", beanName);
            }

        }
    }
}

具體的BeanDefinitionParser實現解析操做,上面的實現比較簡單就是將對應標籤的屬性值取出來而後構建出具體的bean。

到這整個擴展schema該進行的操做就都已經就緒了。

0x05 使用配置

spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:liutxer="http://code.liutxer.com/schema/bymq"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.liutxer.com/schema/bymq http://code.liutxer.com/schema/bymq/rpc.xsd ">

    <bean id="kkk" class="com.liutxer.bymq.conf.DemoTest"></bean>

    <liutxer:service id="jjj" interface="com.liutxer.bymq.conf.IDemoTest" ref="kkk"/>

    <liutxer:reference id="demoTest" interface="com.liutxer.bymq.conf.IDemoTest"></liutxer:reference>
</beans>

這裏經過spring的配置對擴展的schema定義配置,當spring容器加載的時候會加載、解析這份自定義的配置,實現擴展。

實例:

加載配置得到自定義的配置對象進行調用。

public class Test {
    
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:app.xml");
        IDemoTest demoTest = (IDemoTest) ctx.getBean("demoTest");
        System.out.println("spring rpc test:" + demoTest.get());
    }

}
相關文章
相關標籤/搜索