spring通过自定义标签干预bean的生成过程

1:原理

在spring解析xml为BeanDefinition的过程中,解析bean标签在解析了6个主要的默认标签标签之后,会调用解析自定义标签,这些自定义标签也是bean标签的子标签,我们可以编写这些自定义标签的处理器,在该注册器内可以通过修改当前的BeanDefinition来达到干预bean的生成的效果,然后注册自定义处理器,注册之后spring在解析自定义标签的时候就会通过标签名注意不带有命名空间获取我们自定义的处理器,并调用。

2:例子

2.1:测试的类

public class SelfDefineTagPeople {
    
    
    private String name;
    private String hobby;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getHobby() {
    
    
        return hobby;
    }

    public void setHobby(String hobby) {
    
    
        this.hobby = hobby;
    }

    @Override
    public String toString() {
    
    
        return "SelfDefineTagPeople{" +
                "name='" + name + '\'' +
                ", hobby='" + hobby + '\'' +
                '}';
    }
}

2.2: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"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <bean id="defineTagPeople" class="yudaosourcecode.selfdefinetag.SelfDefineTagPeople">
        <property name="name" value="姚明"/>
        <property name="hobby" value="篮球"/>
    </bean>
</beans>

2.3:测试代码

@Test
public void testSelfDefineTag() {
    
    
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("testselfdefinetag.xml");
    SelfDefineTagPeople selfDefineTagPeople = ac.getBean("defineTagPeople", SelfDefineTagPeople.class);
    System.out.println(selfDefineTagPeople);
}

运行:

SelfDefineTagPeople{name='姚明', hobby='篮球'}

Process finished with exit code 0

可以看到是name='姚明', hobby='篮球',我们接下来通过自定义标签将名称修改为张继科,爱好修改为乒乓球

3:改造例子

我们要实现的效果是,通过自定义标签,来修改通过property标签配置的属性值为我们自定义标签配置的属性值。
第一步当然是定义xsd约束文件,如下:

3.1:xsd

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://dongshi.mummy.com/schema/ok"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://dongshi.mummy.com/schema/ok"
            elementFormDefault="qualified">
    <!-- 定义替换属性的顶层标签 -->
    <xsd:element name="propreplacer" type="myreplacer">
        <xsd:annotation>
            <xsd:documentation><![CDATA[ The service config ]]></xsd:documentation>
        </xsd:annotation>
    </xsd:element>

    <!-- 定义用于执行替换的属性 -->
    <xsd:complexType name="myreplacer">
        <!-- 需要替换的属性的名称,多个以逗号分割 -->
        <xsd:attribute name="needReplacePropName" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
        <!-- 需要替换的属性的值,多个以逗号分割 -->
        <xsd:attribute name="needReplacePropValue" type="xsd:string">
            <xsd:annotation>
                <xsd:documentation><![CDATA[ The name of the bean. ]]></xsd:documentation>
            </xsd:annotation>
        </xsd:attribute>
    </xsd:complexType>
</xsd:schema>

这里我们的命名空间是http://dongshi.mummy.com/schema/ok

3.2:创建spring.schema

在resources下创建META-INF,然后创建spring.schema:

http\://dongshi.mummy.com/schema/ok/dongshimummy-2.0.xsd=./dongshimummy-2.0.xsd

3.3:定义处理自定义标签处理器

已经加了比较详细的注释,如下:

public class DonshiMummyNamespaceHandler extends NamespaceHandlerSupport {
    
    
    @Override
    public void init() {
    
    
        System.out.println("kkkkkkkkkkkkkkkkkkkkkk");
        // 这里是关键,"propreplacer"是标签名,value是我们自定义的装饰器
        this.registerBeanDefinitionDecorator("propreplacer", new BeanDefinitionDecorator() {
    
    
            @Override
            public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
    
    
                System.out.println("动态修改属性开始");
                // 通过holder获取BeanDefinition
                BeanDefinition beanDefinition = definition.getBeanDefinition();
                // 强转为Element
                Element element = (Element)node;
                // <dongshimummy:propreplacer needReplacePropName="hobby" needReplacePropValue="足球"/>
                // 获取要修改的属性信息
                String needReplacePropName = element.getAttribute("needReplacePropName");
                System.out.println("needReplacePropName value is: " + needReplacePropName);
                // 获取属性值信息
                String needReplacePropValue = element.getAttribute("needReplacePropValue");
                System.out.println("needReplacePropValue value is: " + needReplacePropValue);
                //MutablePropertyValues propertyValues = new MutablePropertyValues();
                // 逗号分割获取数组
                String[] needReplacePropNameArr = StringUtils.commaDelimitedListToStringArray(needReplacePropName);
                String[] needReplacePropValueArr = StringUtils.commaDelimitedListToStringArray(needReplacePropValue);
                // 获取封装属性和其值信息的对象MutablePropertyValues
                MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
                // 循环数组,设置新的属性值
                for (int i = 0; i < needReplacePropNameArr.length; i++) {
    
    
                    propertyValues.addPropertyValue(needReplacePropNameArr[i], needReplacePropValueArr[i]);
                }
                System.out.println("动态修改属性结束");
                return definition;
            }
        });
    }
}

在META-INF下创建spring.handlers文件,注册自定义标签的处理器,如下:

http\://dongshi.mummy.com/schema/ok=yudaosourcecode.selfdefinetag.DonshiMummyNamespaceHandler

意思是命名空间http\://dongshi.mummy.com/schema/ok使用标签处理器yudaosourcecode.selfdefinetag.DonshiMummyNamespaceHandler

3.4: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:dongshimummy="http://dongshi.mummy.com/schema/ok"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://dongshi.mummy.com/schema/ok
           http://dongshi.mummy.com/schema/ok/dongshimummy-2.0.xsd">
    <bean id="defineTagPeople" class="yudaosourcecode.selfdefinetag.SelfDefineTagPeople">
        <property name="name" value="姚明"/>
        <property name="hobby" value="篮球"/>

        <!-- 自定义标签替换bean的name属性的hobby属性的值 -->
        <dongshimummy:propreplacer needReplacePropName="name,hobby" needReplacePropValue="张继科,乒乓球"/>
    </bean>
</beans>

3.5:测试代码

@Test
public void testSelfDefineTag() {
    
    
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("testselfdefinetag.xml");
    SelfDefineTagPeople selfDefineTagPeople = ac.getBean("defineTagPeople", SelfDefineTagPeople.class);
    System.out.println(selfDefineTagPeople);
}

运行:

kkkkkkkkkkkkkkkkkkkkkk
动态修改属性开始
needReplacePropName value is: name,hobby
needReplacePropValue value is: 张继科,乒乓球
动态修改属性结束
SelfDefineTagPeople{name='张继科', hobby='乒乓球'}

Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/wang0907/article/details/114435126