• 【spring源码学习】spring的IOC容器之自定义xml配置标签扩展namspaceHandler向IOC容器中注册bean


    【spring以及第三方jar的案例】在spring中的aop相关配置的标签,线程池相关配置的标签,都是基于该种方式实现的。包括dubbo的配置标签都是基于该方式实现的。
    【一】原理

    ===>spring在解析xml标签,一旦不是以<bean>开头的元素,就会走org.springframework.beans.factory.xml.BeanDefinitionParserDelegate的parseCustomElement(Element ele)方法解析自定义的标签

    ===>在该方法里会根据xml中的命名空间去查询该标签对应的NamespaceHandler接口的实现类去解析该配置标签。该接口解析该配置标签,并形成BeanDefinition注册到IOC容器中。

    ===>该扩展需要做的内容:

    (1)建立spring.handlers文件,这是在解析xml配置文件的时候,spring会通过xml文件头的命名空间,去找该配置文件中的NamespaceHandler的实现类。

    (2)建立spring.schemas文件,这是在xml文件中配置自定义标签的标签合法验证,也是合法检验。如果随意填写配置标签,spring将无法解析。

    (3)在所扩展的项目的resources目录下,建立META-INF目录,并将两个文件放置在目录下。

    (4)将spring.schemas中的xsd文件配置在随意的类路径下。关于xsd文件,可以了解:http://www.w3school.com.cn/schema/index.asp

    (5)建立NamespaceHandler接口的实现类,建立BeanDefinitionParser的实现类。用于解析自已定义标签的内容。

    【二】实现例子:定义一个自定义标签,实现一个类ZKClient的bean通过NamespaceHandler注册IOC容器。本例子已经通过测试。不写测试方法,只写实现过程。

    (1)spring.handlers文件内容

    http://localhost.com/sxf=com.mobile.thinks.manages.namespaceHandler.SxfNameSpaceHandler
    View Code

    (2)spring.schemas文件内容

    http://localhost.com/sxf.xsd=com/mobile/thinks/manages/namespaceHandler/sxf.xsd
    View Code

    (3)xsd文件内容

    <xsd:schema  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://localhost.com/sxf"
    xmlns="http://www.w3school.com.cn"
    elementFormDefault="qualified">
    
    <xsd:element name="zk">
      <xsd:complexType>
        <xsd:attribute name="host"  use="required" >
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string"/>
                </xsd:simpleType>
        </xsd:attribute>
        <xsd:attribute name="port"  use="required" >
                <xsd:simpleType>
                    <xsd:restriction base="xsd:integer"/>
                </xsd:simpleType>
        </xsd:attribute>
        <xsd:attribute name="user"  use="required" >
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string"/>
                </xsd:simpleType>
        </xsd:attribute>
         <xsd:attribute name="pwd"  use="required" >
                <xsd:simpleType>
                    <xsd:restriction base="xsd:string"/>
                </xsd:simpleType>
        </xsd:attribute>
      </xsd:complexType>
    </xsd:element>
    </xsd:schema>
    View Code

    (4)spring的xml配置文件内容

    <?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:tx="http://www.springframework.org/schema/tx"
           xmlns:jpa="http://www.springframework.org/schema/data/jpa"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:task="http://www.springframework.org/schema/task"
           xmlns:sxf="http://localhost.com/sxf"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/tx
                  http://www.springframework.org/schema/tx/spring-tx.xsd
                  http://www.springframework.org/schema/aop 
                  http://www.springframework.org/schema/aop/spring-aop.xsd
                  http://www.springframework.org/schema/task
                  http://www.springframework.org/schema/task/spring-task.xsd
                  http://www.springframework.org/schema/data/jpa
               http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
               http://www.springframework.org/schema/context 
               http://www.springframework.org/schema/context/spring-context.xsd
               http://localhost.com/sxf
               http://localhost.com/sxf.xsd
               
               ">
    
        <sxf:zk host="127.0.0.1" port="2181" user="shangxiaofei"  pwd="smxcyx"/>
    
       <!-- <context:property-placeholder location="classpath:resources.properties"/> -->
    
        <!-- 扫描注解Bean -->
        <context:component-scan base-package="com.mobile.thinks.**">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
            <context:include-filter type="annotation" expression="org.springframework.beans.factory.annotation.Autowired"/>
        </context:component-scan>
        
       
        
    </beans>
    View Code

    (5)NamespaceHandler接口实现类的内容

    package com.mobile.thinks.manages.namespaceHandler;
    
    import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
    /**
     * 自定义标签的注解解释器
     * @author sxf
     *
     */
    public class SxfNameSpaceHandler extends NamespaceHandlerSupport {
    
        /**
         * 初始化zk元素的具体解析器
         */
        @Override
        public void init() {
            registerBeanDefinitionParser("zk", new ZkBeanDefinitionParser());
        }
        
    
    }
    View Code

    (6)BeanDefinitionParser接口实现类的内容

    package com.mobile.thinks.manages.namespaceHandler;
    
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.xml.BeanDefinitionParser;
    import org.springframework.beans.factory.xml.ParserContext;
    import org.w3c.dom.Element;
    
    public class ZkBeanDefinitionParser  implements BeanDefinitionParser{
    
        private static final String HOST ="host";
        private static final String PORT="port";
        private static final String USER="user";
        private static final String PWD="pwd";
        
        /**
         * 解析标签,形成特定的beanDefinition加入到ioc容器中
         */
        @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ZkClient.class);
            String host=element.getAttribute("host");
            String port=element.getAttribute("port");
            String user=element.getAttribute("user");
            String pwd=element.getAttribute("pwd");
            builder.addPropertyValue("host",host);
            builder.addPropertyValue("port", Integer.valueOf(port));
            builder.addPropertyValue("user", user);
            builder.addPropertyValue("pwd", pwd);
            parserContext.getRegistry().registerBeanDefinition("zkClient", builder.getBeanDefinition());
            return builder.getBeanDefinition();
        }
        
        
    
    }
    View Code

    (7)Zkclient类的内容,将来在项目中用一下方式直接使用该类

     @Autowired
        private ZkClient zkClient;

    package com.mobile.thinks.manages.namespaceHandler;
    /**
     * 该类用自定义的NameSpaceHandler类解析配置文件向IOC容器中注册
     * @author sxf
     *
     */
    public class ZkClient {
    
        private String host;
        private int port;
        private String user;
        private String pwd;
        
        public String getHost() {
            return host;
        }
        public void setHost(String host) {
            this.host = host;
        }
        public int getPort() {
            return port;
        }
        public void setPort(int port) {
            this.port = port;
        }
        public String getUser() {
            return user;
        }
        public void setUser(String user) {
            this.user = user;
        }
        public String getPwd() {
            return pwd;
        }
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
        
    }
    View Code

    【三】项目结构图

    【&&】需要注意的点,当maven打包的时候,默认不会将sxf.xsd文件打包进jar包,将来项目用到的时候就不会从本地读取到该sxf.xsd文件,则需要在pom.xml文件配置如下,才可以将文件打包到相应的位置。也可以将其他格式的文件,打包到jar包相应的位置,只需要修改相应文件的后缀。

    <build>    
              <!-- 打成jar包的名字 -->
            <finalName>test</finalName>    
            <!--  这样也可以把所有的readme文件,打包到相应位置。其他的比如XX.xml文件,也是同样配置  -->  
            <resources>    
                <resource>    
                    <directory>src/main/resources</directory>    
                    <includes>    
                        <include>**/*.txt</include>    
                        <include>**/*.xml</include>  
                    </includes>    
                </resource>    
                <resource>    
                    <directory>src/main/java</directory>    
                    <includes>    
                        <include>**/*.xsd</include>  
                    </includes>     
                </resource>    
            </resources>    
        </build>    
    View Code

    该项目的jar完整的pom.xml文件

    <?xml version="1.0"?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>com.mobile</groupId>
        <artifactId>thinks</artifactId>
        <version>0.0.1-SNAPSHOT</version>
      </parent>
      <groupId>com.mobile</groupId>
      <artifactId>thinks-manages</artifactId>
      <version>1.0.0</version>
      <name>thinks-manages</name>
      <url>http://maven.apache.org</url>
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
          <build>    
            <!--  <finalName>test</finalName> 打包成默认名字 -->   
            <!--  这样也可以把所有的readme文件,打包到相应位置。其他的比如XX.xml文件,也是同样配置  -->  
            <resources>    
                <resource>    
                    <directory>src/main/resources</directory>    
                    <includes>    
                        <include>**/*.txt</include>    
                        <include>**/*.xml</include>
                        <include>**/*.handlers</include>
                        <include>**/*.schemas</include>
                        <include>**/*.drl</include>  
                    </includes>    
                </resource>    
                <resource>    
                    <directory>src/main/java</directory>    
                    <includes>    
                        <include>**/*.xsd</include>  
                    </includes>     
                </resource>    
            </resources>    
        </build>    
      <dependencies>
          <dependency>
              <groupId>com.mobile</groupId>
              <artifactId>thinks-service</artifactId>
              <version>${thinks.service.version}</version>
          </dependency>
          <dependency>
              <groupId>com.mobile</groupId>
              <artifactId>thinks-core</artifactId>
              <version>${thinks.core.version}</version>
          </dependency>
          <dependency>
              <groupId>com.mobile</groupId>
              <artifactId>thinks-commons</artifactId>
              <version>${thinks.commons.version}</version>
          </dependency>
      
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
        
        <!-- drools规则引擎 -->
        <dependency>
                    <groupId>org.drools</groupId>
                    <artifactId>drools-core</artifactId>
                </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-compiler</artifactId>
            </dependency>
            <dependency>
              <groupId>org.drools</groupId>
              <artifactId>knowledge-api</artifactId>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-decisiontables</artifactId>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-jsr94</artifactId>
                <version>${drools.version}</version><!--$NO-MVN-MAN-VER$-->
            </dependency>
              <!-- drools升级6.5.0.final版本依赖 -->
            <dependency>
                    <groupId>org.eclipse.jdt.core.compiler</groupId>
                    <artifactId>ecj</artifactId>
            </dependency>
      </dependencies>
    </project>
    View Code

    ================xsd文件定义语法================

    1. xsd:element     表示定义标签  
    2. xsd:extension  如java中的继承,把现有的定义继承进来  
    3. xsd:attribute    标签带有的属性  
    4. xsd:restriction  对标签改属性进一步的限制,进行一些值的约束 
  • 相关阅读:
    使用GO操作MongoDB
    解决golang时间字符串转time.Time的坑
    [Exercises on 2022.5.3] Dynamic Programming
    [Contest on 2022.5.13] 再这样熬夜我就要猝死了
    合成史莱姆
    [Contest on 2022.5.4] 痛啊!上周真的直接摆过去了!
    [Exercises on 2022.5.11] 字符串转风车煮饭吃蒸饭吃脂肪层
    [Contest on 2022.5.6] 手写 bitset 模板
    CodeForces 547E Mike and Friends
    [Contest on 2022.5.2] 端午节能放几天啊?
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/7235556.html
Copyright © 2020-2023  润新知