spring默认提供的标签,我们常用的bean标签,property,constructor-arg等,spring也允许我们自定义标签。
我们这里以xsd
约束文件为例,来简单描述,首先需要有一个xsd的约束文件,然后需要有一个spring.schema文件来描述命名空间和xsd文件的对应关系,这些在自定义标签的时候也是必不可少的,除此之外我们自定义的标签还需要一个解析的类,因此还需要有这样的一个类,在spring中这个类必须实现org.springframework.beans.factory.xml.NamespaceHandler
接口,实际中我们只需要继承org.springframework.beans.factory.xml.NamespaceHandlerSupport
抽象子类就可以了,下面就让我们一个一个的实现这些必须条件
吧。
自定义标签,实现bean
标签的作用,即完成创建一个spring bean的工作。
<xsd:schema xmlns="http://dongshi.daddy.com/schema/ok"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://dongshi.daddy.com/schema/ok"
elementFormDefault="qualified">
<xsd:element name="service" type="server">
<xsd:annotation>
<xsd:documentation>xsd:documentation>
xsd:annotation>
xsd:element>
<xsd:complexType name="server">
<xsd:attribute name="id" type="xsd:string">
<xsd:annotation>
<xsd:documentation>xsd:documentation>
xsd:annotation>
xsd:attribute>
<xsd:attribute name="serverName" type="xsd:string">
<xsd:annotation>
<xsd:documentation>xsd:documentation>
xsd:annotation>
xsd:attribute>
xsd:complexType>
xsd:schema>
表达的含义是,在service标签中可以有id属性,serverName属性。最后将该文件放在resources
资源文件目录下,文件命名为dongshidaddy-1.0.xsd
,后续配置会用到该名称。其中的targetNamespace="http://dongshi.daddy.com/schema/ok"
是设置该约束文件的命名空间是http://dongshi.daddy.com/schema/ok
。
需要在spring.schemas
中配置,并且该文件需要放在classpath下的META-INF
文件夹下,因此需要先在resources下定义该文件夹,定义内容如下:
http\://dongshi.daddy.com/schema/ok/ok-1.0.xsd=./dongshidaddy-1.0.xsd
注意实现接口org.springframework.beans.factory.xml.BeanDefinitionParser
,主要代码已经添加了注释:
public class CommonNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
this.registerBeanDefinitionParser("service",
new OkServerDefinitionParser(ServerBean.class));
}
}
OkServerDefinitionParser:
public class OkServerDefinitionParser implements BeanDefinitionParser {
private final Class<?> clazz;
private static final String default_prefix = "ok-";
private static final AtomicLong COUNT = new AtomicLong(0);
public OkServerDefinitionParser(Class<?> clazz) {
this.clazz = clazz;
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return parseHelper(element, parserContext, this.clazz);
}
private BeanDefinition parseHelper(Element element, ParserContext parserContext, Class<?> clazz) {
// 创建封装信息的beandefinition
RootBeanDefinition bd = new RootBeanDefinition();
// 不延迟加载
bd.setLazyInit(false);
String id = element.getAttribute("id");
if (id == null || id.isEmpty()) {
id = default_prefix + COUNT.getAndDecrement();
}
// 获取配置的serverName的值
String serverName = element.getAttribute("serverName");
// 设置class
bd.setBeanClass(clazz);
// 设置初始化方法的名称
bd.setInitMethodName("init");
// 从beandefinition中获取存储属性名称->属性值新的对象
MutablePropertyValues propertyValues = bd.getPropertyValues();
// 添加serverName属性和其值到可修改属性值对象中
propertyValues.addPropertyValue("serverName", serverName);
// 通过注册机注册BeanDefinition信息,最终会存储到一个map中,key就是id,value就是BeanDefinition
parserContext.getRegistry().registerBeanDefinition(id, bd);
// 返回创建的BeanDefinition,后续spring就会使用这个BeanDefinition对象来创建spring bean了
return bd;
}
}
ServerBean:
public class ServerBean {
private String serverName;
//init method
public void init() {
System.out.println("bean ServerBean init.");
}
@Override
public String toString() {
return "[Service]=>" + serverName;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
}
在META-INF
下创建文件spring.handlers
文件,如下:
http\://dongshi.daddy.com/schema/ok=yudaosourcecode.selfdefinetag.CommonNamespaceHandler
意思是如果是命名空间是http\://dongshi.daddy.com/schema/ok
则使用解析类yudaosourcecode.selfdefinetag.CommonNamespaceHandler
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ok="http://dongshi.daddy.com/schema/ok"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://dongshi.daddy.com/schema/ok
http://dongshi.daddy.com/schema/ok/dongshidaddy-1.0.xsd">
<ok:service id="testServer" serverName="HelloWorldService"/>
beans>
其中xmlns:ok="http://dongshi.daddy.com/schema/ok"
定了命名空间http://dongshi.daddy.com/schema/ok
使用前缀xsi:schemaLocation
中声明了约束文件的位置。
@Test
public voidtestSelfDefineTag() {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("testselfdefinetag.xml");
ServerBean testServer = ac.getBean("testServer", ServerBean.class);
System.out.println(testServer);
}
运行:
bean ServerBean init.
[Service]=>HelloWorldService
Process finished with exit code 0