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