spring中的自定义名称空间是用更友好的配置替换复杂bean定义的一种方式
文章目录
-
Spring 本身提供了几个现成的名称空间。例如<mvc:annotation-driven/>, 有关<mvc:annotation-driven/>,的翻译,请参考此帖子
-
让我们以示例场景为例,并逐步执行创建自定义名称空间以及处理程序的步骤。
-
命名空间的例子
-
考虑如下类:
-
// dao类 public class MyDAO { private List<String> fields; public List<String> getFields() { return fields; } public void setFields(List<String> fields) { this.fields = fields; } } // 服务类 public class MyService { private String serviceName; private MyDAO defaultDao; private Map<String, MyDAO> daoRegistry; public String getServiceName() { return serviceName; } public void setServiceName(String serviceName) { this.serviceName = serviceName; } public MyDAO getDefaultDao() { return defaultDao; } public void setDefaultDao(MyDAO defaultDao) { this.defaultDao = defaultDao; } public Map<String, MyDAO> getDaoRegistry() { return daoRegistry; } public void setDaoRegistry(Map<String, MyDAO> daoRegistry) { this.daoRegistry = daoRegistry; } }
-
假设我们使用以下一组bean实例化这些类
-
<bean id="myservice-123" class="com.codelooru.dos.MyService"> <property name="defaultDao" ref="mydao-123" /> <property name="serviceName" value="myservice" /> <property name="daoRegistry"> <map> <entry key="dao1" value-ref="mydao-123" /> </map> </property> </bean> <bean id="mydao-123" class="com.codelooru.dos.MyDAO"> <property name="fields"> <list> <value>field1</value> <value>field2</value> <value>field3</value> </list> </property> </bean>
-
-
现在,我想用非常简单的内容替换这些Bean定义,例如:
-
<createservice daoid="mydao-123" fields="field1,field2,field3" serviceid="myservice-123"> </createservice>
-
第一步:Schema定义
-
为我们的自定义XML元素定义Schema
-
createservice元素的schema如下,自定义命名空间为http://www.codelooru.com/custns
-
<xs:schema elementformdefault="qualified" targetnamespace="http://www.codelooru.com/custns" xmlns:tns="http://www.codelooru.com/custns" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="createservice"> <xs:complextype> <xs:attribute name="serviceId" type="xs:string" use="required"> <xs:attribute name="daoId" type="xs:string" use="required"> <xs:attribute name="fields" type="xs:string" use="required"> </xs:attribute></xs:attribute></xs:attribute></xs:complextype> </xs:element> </xs:schema>
第二步:NameSpaceHandler(命名空间处理器)
-
为上述定义的命名空间创建命名空间处理程序,定制命名空间处理程序应实现org.springframework.beans.factory.xml.NamespaceHandler接口。Spring提供了一个便利类org.springframework.beans.factory.xml.NamespaceHandlerSupport, 该类提供了一种通过单个处理程序注册多个命名空间解析器的方法。
-
public class CustomNamespaceHandler extends NamespaceHandlerSupport { public void init() { registerBeanDefinitionParser("createservice", new CreateServiceNamespaceBeanDefinitionParser()); } }
-
init方法应为所需元素注册所有bean定义解析器。
-
对于createservice元素,我们将定义一个新的BeanDefinitionparser, 这将在第5步中详细介绍
第三步 spring.handlers
-
在META-INF下创建文件"spring.handlers", 并为名称空间注册处理程序。
-
http\://www.codelooru.com/custns=com.codelooru.custns.CustomNamespaceHandler
-
当Spring Bean XML 中遇到名称空间时,Spring会调用此处理程序
第四步 spring.schemas
-
在META-INF下创建文件"spring.schemas", 并注册命名空间的schema定义文件。
-
http\://www.codelooru.com/custns.xsd=schema.xsd
-
Spring会根据提供的schema定义来验证bean XML中的元素
第五步 BeanDefinitionParser
-
创建一个自定义的BeanDefinitionParser, 它将解析createservice元素并生成bean 定义。 解析器应实现org.springframework.beans.factory.xml.BeanDefinitionParser.
-
public class CreateServiceNamespaceBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext parserContext) { //parsing <custns:abcd service="myservice" dao="mydao" fields="field1,field2,field3"/> BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyDAO.class); builder.addPropertyValue("fields", Arrays.asList(element.getAttribute("fields").split(","))); String daoId = element.getAttribute("daoId"); parserContext.getRegistry().registerBeanDefinition(daoId, builder.getBeanDefinition()); ManagedMap<Object, Object> map = new ManagedMap<Object, Object>(); map.put("dao1", new RuntimeBeanReference(daoId)); builder = BeanDefinitionBuilder.genericBeanDefinition(MyService.class); builder.addPropertyValue("serviceName", "myservice"); builder.addPropertyReference("defaultDao", daoId); builder.addPropertyValue("daoRegistry", map); parserContext.getRegistry().registerBeanDefinition(element.getAttribute("serviceId"), builder.getBeanDefinition()); return null; } }
- 实现parse方法,该方法为createservice元素和ParserContext提供org.w3c.dom.Element对象。
- ParserContext为您提供访问BeanDefinitionRegistry的权限,我们将使用它来注册我们的bean
- BeanDefinitionBuilder.genericBeanDefinition(Someclass), 为提供的类创建一个新的bean定义
- 您可以通过在构建器上使用addPropertyValue来设置属性的值。第一个参数将是属性名称,第二个参数将是实际值。值可以是任何类型。
- 如果要为引用bean设置属性,请使用RuntimeBeanReference.
- 如果您的值是具有一个或多个引用的列表,请使用org.springframework.beans.factory.support.ManagedList定义列表。
- 如果您的值是具有一个或多个引用的map,请使用org.springframework.beans.factory.support.ManagedMap定义Map。
- 您可以使用addPropertyReference将属性设置为引用另一个bean。第一个参数将是属性名称,第二个参数将是被引用bean的名称。
- 一旦定义了bean,就可以通过parserContext.getRegistry(). registerBeanDefinition方法进行注册。它以bean的id作为第一个参数,以BeanDefinition作为第二个参数。