Spring自定义xml标签

本文详细介绍了如何在Spring中自定义XML标签,包括编写标签schema,设置spring.schemas和spring.handlers文件,创建namespaceHandler和BeanDefinitionParser。自定义标签涉及到的namespaceHandler负责注册解析器,BeanDefinitionParser用于从XML元素中抽取信息生成BeanDefinition。同时,文章讨论了如何通过FactoryBean和InitializingBean接口实现个性化bean的生成,并给出了使用自定义XML标签的指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、总体思路:

1.1) 编写标签schema

1.2) 添加文件spring.schemasspring.handlers(目录固定在classpath:/META-INF下,被依赖代码必须打成一个jar包)

1.3) 编写一堆handler


2、详细说明

自定义的标签一定有属于自己的namespace,所以要有个namespaceHandler(继承NamespaceHandlerSupport),这个handler的作用就是注册自定义标签的parser,且该handler的全称必须写在spring.handlers里。



自定义标签也需要引入namespace,这个namespace全称及schema文件所在路径就写在spring.schemas文件里(与文件spring.handlers同目录)。



自定义的每一种标签都对应一个parser(实现接口BeanDefinitionParser)和beanClassparser就是从xmlelement中抽取相关信息,生成一个BeanDefinition(如GenericBeanDefinition)实例definition,并将beanClassbeanNamepropertyValue赋给definition,最后将definition注册到ParserContext里。

beanName可以调用spring提供的id生成器

String beanName = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry());


这里的propertyValue是用来给新newbeanClass的成员字段赋值用的。propertyValue是一个ListList中每个成员(key是成员字段名,value是成员字段值类型此处是Object)都对应beanClass的一个成员字段。

这里的beanClass可以实现FactoryBeanInitializingBean来生成个性化的bean



FactoryBean有个接口public T getObject(){}spring在实例化完一个bean之后,判断下该bean是否实现了FactoryBean接口,如果实现了,那么调用下getObject()接口,以返回值作为真正的bean实例。

InitializingBean有个接口public void afterPropertiesSet()springnew一个bean对象,并且完成该对象的成员字段的赋值后,调用下该接口(注意getObject是在该接口之后才调用)。



3、使用自定义的xml标签

<beans
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:sg="http://code.sample.com/schema/sg"
       
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        
    http://www.springframework.org/schema/beans/spring-beans.xsd
        
    http://code.sample.com/schema/sg
        
    http://code.sample.com/schema/sg/sg.xsd">
    <sg:property-placeholder location="classpath*:conf/sample.properties"/>
    <sg:application container-id="${sample.container.id}" container-port="${sample.container.default.port}"
                    
    register-http="${sample.governance.http.address}" register-tcp="${sample.governance.tcp.address}"
                    
    service-gateway="${sample.gateway.address}"/>
    <sg:consume id="faceBundleImpBundle" providerId="${sample.provider.providerId}"
                
    service="FaceBundleImpBundle" version="${sample.provider.version}" protocol="navi2json"
                interfaceType="com.sample.fbu.sample.agent.test.api.FaceBundleImpBundle"/>
    <sg:consume id="faceBundleImpNoBundle" providerId="${sample.provider.providerId}"
                
    service="FaceBundleImpNoBundle" version="${sample.provider.version}" protocol="navi2json"
                interfaceType="com.sample.fbu.sample.agent.test.api.FaceBundleImpNoBundle"/>
    <sg:consume id="faceNoBundleImpBundle" providerId="${sample.provider.providerId}"
                
    service="FaceNoBundleImpBundle" version="${sample.provider.version}" protocol="navi2json"
                interfaceType="com.sample.fbu.sample.agent.test.api.FaceNoBundleImpBundle"/>
    <sg:consume id="faceNoBundleImpNoBundle" providerId="${sample.provider.providerId}"
                
    service="FaceNoBundleImpNoBundle" version="${sample.provider.version}" protocol="navi2json"
                interfaceType="com.sample.fbu.sample.agent.test.api.FaceNoBundleImpNoBundle"/>
    <sg:extend-property>
        <sg:property key="sample.governance.gateway.ask.interval" value="30000"/>
        <sg:property key="sample.service.auto-register" value="true"/>
        <sg:property key="sample.service.requestlog" value="true"/>
        <sg:property key="sample.governance.isolate.policy" value="QualityScore"/>
        <sg:property key="sample.rpc.security.provider.key.1.(.+)" value="portal!Q@W#E$R"/>
    </sg:extend-property>
    <bean class="com.sample.ub.sample.container.support.bundle.ExtBundleContextPostProcessor">
        <constructor-arg name="bundleName" value="consumerService"/>
    </bean>
</beans>




4、自定义xml标签的schema定义

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xsd:schema
    xmlns="http://code.sample.com/schema/sg">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:import namespace="http://www.springframework.org/schema/beans" />
    <xsd:import namespace="http://www.springframework.org/schema/tool" />
    <xsd:annotation>
        <xsd:documentation>
            <![CDATA[ Namespace support for the service gateway.]]>
        </xsd:documentation>
    </xsd:annotation>
    <xsd:simpleType name="protocolType">
        <xsd:restriction base="xsd:NMTOKENS">
            <xsd:enumeration value="navi2json" />
            <xsd:enumeration value="navi2proto" />
            <xsd:enumeration value="navi" />
            <xsd:enumeration value="pbrpc" />
            <xsd:enumeration value="jsonrpc" />
            <xsd:enumeration value="msgpack" />
        </xsd:restriction>
    </xsd:simpleType>
    <xsd:complexType name="abstractType">
        <xsd:attribute name="service" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The service name. ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="version" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ the service's version, should be an integer. ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="interfaceType" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ the interface type of that service. ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="protocol" type="protocolType" use="optional">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ the protocol type for rpc. ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>
    <xsd:complexType name="providerType">
        <xsd:complexContent>
            <xsd:extension base="abstractType">
                <xsd:attribute name="routeStrategy" use="optional">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:NMTOKENS">
                            <xsd:enumeration value="local" />
                            <xsd:enumeration value="remote" />
                            <xsd:enumeration value="switchover" />
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:attribute>
                <xsd:attribute name="ref" type="xsd:string">
                    <xsd:annotation>
                        <xsd:documentation>
                            <![CDATA[ the beanId of service which will be used in current project.
]]>
                        </xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:complexType name="consumerType">
        <xsd:complexContent>
            <xsd:extension base="abstractType">
                <xsd:attribute name="providerId" type="xsd:string" use="optional">
                    <xsd:annotation>
                        <xsd:documentation>
                            <![CDATA[ The provider id. ]]>
                        </xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>
                <xsd:attribute name="selectStrategy" use="optional">
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:NMTOKENS">
                            <xsd:enumeration value="random" />
                            <xsd:enumeration value="local_preference" />
                            <xsd:enumeration value="remote_preference" />
                            <xsd:enumeration value="high_available" />
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:attribute>
                <xsd:attribute name="id" type="xsd:string">
                    <xsd:annotation>
                        <xsd:documentation>
                            <![CDATA[ the beanId of service which will be used in current project.
]]>
                        </xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:complexType name="applicationType">
        <xsd:attribute name="container-id" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The provider id. ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="container-port" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The port of your service. ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="register-http" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The http address of register-center. Separated by
comma ',', if you have multi addresses.]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="register-tcp" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The tcp address of register-center. Separated by
comma ',', if you have multi addresses.]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="service-gateway" type="xsd:string" use="optional">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The address of service gateway. Separated by
comma ',', if you have multi addresses.]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>
    <xsd:complexType name="propertyType">
        <xsd:attribute name="key" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The name of property.]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="value" type="xsd:string" use="required">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[ The value of property.]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>
    <xsd:complexType name="emptyType"></xsd:complexType>
    <xsd:complexType name="extendPropertyType">
        <xsd:complexContent>
            <xsd:extension base="emptyType">
                <xsd:choice>
                    <xsd:element ref="property" minOccurs="1" maxOccurs="unbounded"></xsd:element>
                </xsd:choice>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:complexType name="propertyLoading">
        <xsd:attribute name="location" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[
     The location of the properties file to resolve placeholders against, as a Spring
       resource location: a URL, a "classpath:" pseudo URL, or a relative file path.
  Multiple locations may be specified, separated by commas. If neither location nor
      properties-ref is specified, placeholders will be resolved against system properties.
                          ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="properties-ref" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation source="java:java.util.Properties">
                    <![CDATA[
    The bean name of a Properties object that will be used for property substitution.
      If neither location nor properties-ref is specified, placeholders will be resolved
     against system properties.
                             ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="file-encoding" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[
        Specifies the encoding to use for parsing properties files. Default is none,
   using the java.util.Properties default encoding. Only applies to classic
       properties files, not to XML files.
                            ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="order" type="xsd:token">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[
 Specifies the order for this placeholder configurer. If more than one is present
       in a context, the order can be important since the first one to be match a
     placeholder will win.
                          ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="ignore-resource-not-found" type="xsd:boolean" default="false">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[
   Specifies if failure to find the property resource location should be ignored.
 Default is "false", meaning that if there is no file in the location specified
 an exception will be raised at runtime.
                                ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="ignore-unresolvable" type="xsd:boolean" default="false">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[
 Specifies if failure to find the property value to replace a key should be ignored.
    Default is "false", meaning that this placeholder configurer will raise an exception
   if it cannot resolve a key. Set to "true" to allow the configurer to pass on the key
   to any others in the context that have not yet visited the key in question.
                            ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <xsd:attribute name="local-override" type="xsd:boolean" default="false">
            <xsd:annotation>
                <xsd:documentation>
                    <![CDATA[
      Specifies whether local properties override properties from files.
     Default is "false": Properties from files override local defaults.
                             ]]>
                </xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>
    <xsd:complexType name="placeholderType">
        <xsd:complexContent>
            <xsd:extension base="propertyLoading">
                <xsd:attribute name="system-properties-mode" default="ENVIRONMENT">
                    <xsd:annotation>
                        <xsd:documentation>
                            <![CDATA[
  Controls how to resolve placeholders against system properties. As of Spring 3.1, this
 attribute value defaults to "ENVIRONMENT", indicating that resolution of placeholders
  against system properties is handled via PropertySourcesPlaceholderConfigurer and its
  delegation to the current Spring Environment object.

  For maximum backward compatibility, this attribute is preserved going forward with the
 3.1 version of the context schema, and any values other than the default "ENVIRONMENT"
 will cause a traditional PropertyPlaceholderConfigurer to be registered instead of the
 newer PropertySourcesPlaceholderConfigurer variant. In this case, the Spring Environment
       and its property sources are not interrogated when resolving placeholders. Users are
   encouraged to consider this attribute deprecated, and to take advantage of the
 Environment and PropertySource mechanisms. See ConfigurableEnvironment javadoc for examples.

  "ENVIRONMENT" indicates placeholders should be resolved against the current Environment and against any local properties;
      "NEVER" indicates placeholders should be resolved only against local properties and never against system properties;
   "FALLBACK" indicates placeholders should be resolved against any local properties and then against system properties;
  "OVERRIDE" indicates placeholders should be resolved first against system properties and then against any local properties;
                                                    ]]>
                        </xsd:documentation>
                    </xsd:annotation>
                    <xsd:simpleType>
                        <xsd:restriction base="xsd:string">
                            <xsd:enumeration value="ENVIRONMENT" />
                            <xsd:enumeration value="NEVER" />
                            <xsd:enumeration value="FALLBACK" />
                            <xsd:enumeration value="OVERRIDE" />
                        </xsd:restriction>
                    </xsd:simpleType>
                </xsd:attribute>
                <xsd:attribute name="value-separator" default=":">
                    <xsd:annotation>
                        <xsd:documentation>
                            <![CDATA[
  The separating character between the placeholder variable and the associated
   default value: by default, a ':' symbol.
                               ]]>
                        </xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>
                <xsd:attribute name="null-value">
                    <xsd:annotation>
                        <xsd:documentation>
                            <![CDATA[
     A value that should be treated as 'null' when resolved as a placeholder value:
 e.g. "" (empty String) or "null". By default, no such null value is defined.
                           ]]>
                        </xsd:documentation>
                    </xsd:annotation>
                </xsd:attribute>
            </xsd:extension>
        </xsd:complexContent>
    </xsd:complexType>
    <xsd:element name="consume" type="consumerType">
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ The config for service provided by others.]]>
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>
    <xsd:element name="provide" type="providerType">
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ The config for service provider by yourself. ]]>
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>
    <xsd:element name="application" type="applicationType">
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ Global application config for yourself. ]]>
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>
    <xsd:element name="property" type="propertyType">
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ One property config. ]]>
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>
    <xsd:element name="extend-property" type="extendPropertyType">
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ Extended property set. ]]>
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>
    <xsd:element name="property-placeholder" type="placeholderType">
        <xsd:annotation>
            <xsd:documentation>
                <![CDATA[ extend of spring property-placeholder.]]>
            </xsd:documentation>
        </xsd:annotation>
    </xsd:element>
</xsd:schema>





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值