老生谈spring(番外一):自定义标签
1、本节我们创建一个自定义的标签customer:supplier,并且通过这个标签使用Java8的Supplier创建Bean。先来看看这个项目的目录,为了实现自定义标签,需要在项目中加入定义自定义标签的xsd文件以及schemal文件。除此之外,还有handlers文件绑定命名空间和它的处理类。
2、首先定义customer.xsd文件,分别定义了一个http://www.cores.org/schema/customer命名空间,这个命名空间下定义了一个supplier元素以及supplier元素的name属性(用来定义beanName)和supplier属性(用来定义supplier的class)。
文件内容如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.cores.org/schema/customer"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.cores.org/schema/customer">
<xsd:complexType name="elementname1complexType">
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The elementname1 name. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="supplier" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The elementname1 supplier. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:element name="supplier" type="elementname1complexType">
</xsd:element>
</xsd:schema>
3、定义好xsd文件后,需要用一个spring.schemas文件去指定这个xsd文件的路径:
http\://www.cores.org/schema/customer.xsd=/META-INF/customer.xsd
4、有了这些定义后,就能在application.xml文件中使用了。现在beans标签中引入customer的命名空间,然后使用customer:supplier标签指定我要创建的bean的名称是a,使用的supplier是cores.factory.ASupplier。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:customer="http://www.cores.org/schema/customer"
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.xsd
http://www.cores.org/schema/customer
http://www.cores.org/schema/customer.xsd ">
<bean id="parse" class="cores.handler.SupplierParse"></bean>
<!-- 自定义标签,使用suplier创建bean-->
<customer:supplier name="a" supplier="cores.factory.ASupplier"/>
</beans>
5、有了这步以后就通过spring.handlers文件绑定customer命名空间的处理类(不知道为什么的同学可以看回自定义标签的文章):
http\://www.cores.org/schema/customer=cores.handler.CustomerHandler
6、这里我的处理类是CustomerHandler,在init方法里绑定supplier标签的处理类:
public class CustomerHandler extends NamespaceHandlerSupport {
@Override
public void init() {
//绑定supplier标签的处理类
registerBeanDefinitionParser("supplier",new SupplierParse());
}
}
7、SupplierParse 就是用来处理supplier标签,首先在parse方法中解析标签的name属性和spupplier属性,创建supplier对象后,赋值给静态变量name和supplier。为什么是静态的呢?因为SupplierParse虽然会被spring创建,但它并不是bean,它不会拥有bean的生命周期,所以这个对象的postProcessBeanDefinitionRegistry是不会执行。所以我在application.xml文件中再创建SupplierParse 这个bean,由于这个bean是和先前的对象不是同一个对象,所以需要从静态属性中获取。
public class SupplierParse implements BeanDefinitionParser, BeanDefinitionRegistryPostProcessor {
private static String name;
private static Supplier supplier;
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
name = element.getAttribute("name");
try {
supplier = (Supplier) ReflectionUtil.createInstance(element.getAttribute("supplier"), this.getClass().getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
//创建并注册beanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setInstanceSupplier(supplier);
registry.registerBeanDefinition(name, beanDefinition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
8、最后就是ASupplier 的代码和A、B类的代码
public class ASupplier implements Supplier<A> {
@Override
public A get() {
return new A(new B());
}
}
public class A {
private B b;
public A(B b){
this.b = b;
System.out.println("a init..");
}
}
public class B {
}
9、执行结果如下: