在spring 2.0 中,增加了自定义xml标记这一重大的功能。下面主要看一下spring 2.0实现这一功能的主要相关类: NamespaceHandlerResolver(接口) 实现类: String location = "org/springframework/beans/factory/xml/support/customNamespace.properties"; 实现类: 实际的操作由具体的BeanDefinitionDecorator 或者BeanDefinitionParser 执行 BeanDefinitionDecorator(接口) 装饰相关的自定义属性。 AbstractInterceptorDrivenBeanDefinitionDecorator 其他类: PluggableSchemaResolver,用于自定义相关的schema,默认的schema 保存于spring.schemas文件中 可以通过覆盖resolveEntity方法来装载相应的自定义xsd文件 主要的执行类: 实际的类,就介绍到这,下一节通过实例来说明如何定义自定义xml 元素 |
看了spring test 用例,其实实现这一功能还算比较简单,主要分以下的步骤,具体的实例可以去参考spring 自带的testcase 首先定义相关xsd文件,用于验证相应的行为:
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
定义Handler: 主要注册相应的解析类和装饰类
publicclass TestNamespaceHandler extends NamespaceHandlerSupport { publicvoid init() { //相对于每个xsd中定义的元素 registerBeanDefinitionParser("testBean", new TestBeanDefinitionParser()); registerBeanDefinitionDecorator("set", new PropertyModifyingBeanDefinitionDecorator()); registerBeanDefinitionDecorator("debug", new DebugBeanDefinitionDecorator()); registerBeanDefinitionDecorator("nop", new NopInterceptorBeanDefinitionDecorator()); registerBeanDefinitionDecoratorForAttribute("object-name", new ObjectNameBeanDefinitionDecorator()); } }
定义各个解析类: privatestaticclass TestBeanDefinitionParser implements BeanDefinitionParser { public BeanDefinition parse(Element element, ParserContext parserContext) { RootBeanDefinition definition = new RootBeanDefinition(); definition.setBeanClass(TestBean.class);
MutablePropertyValues mpvs = new MutablePropertyValues(); mpvs.addPropertyValue("name", element.getAttribute("name")); mpvs.addPropertyValue("age", element.getAttribute("age")); definition.setPropertyValues(mpvs);
parserContext.getRegistry().registerBeanDefinition(element.getAttribute("id"), definition);
returnnull; } } privatestaticclassPropertyModifyingBeanDefinitionDecorator implements BeanDefinitionDecorator { public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { Element element = (Element)node; BeanDefinition def = definition.getBeanDefinition();
MutablePropertyValues mpvs = (def.getPropertyValues() == null) ? new MutablePropertyValues() : def.getPropertyValues(); mpvs.addPropertyValue("name", element.getAttribute("name")); mpvs.addPropertyValue("age", element.getAttribute("age"));
((AbstractBeanDefinition) def).setPropertyValues(mpvs); return definition; } } privatestaticclassDebugBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator {
protected BeanDefinition createInterceptorDefinition(Node node) { returnnew RootBeanDefinition(DebugInterceptor.class); } } privatestaticclassNopInterceptorBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator {
protected BeanDefinition createInterceptorDefinition(Node node) { returnnew RootBeanDefinition(NopInterceptor.class); } } privatestaticclassObjectNameBeanDefinitionDecorator implements BeanDefinitionDecorator { public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) { Attr objectNameAttribute = (Attr)node; definition.getBeanDefinition().setAttribute("objectName", objectNameAttribute.getValue()); return definition; } }
可以定义EntityResolver,用于验证相应的xsd privateclass DummySchemaResolver extends PluggableSchemaResolver {
public DummySchemaResolver() { super(CustomNamespaceHandlerTests.this.getClass().getClassLoader()); }
public InputSource resolveEntity(String publicId, String systemId) throws IOException { InputSource source = super.resolveEntity(publicId, systemId); if (source == null) { Resource resource = source = new InputSource(resource.getInputStream()); source.setPublicId(publicId); source.setSystemId(systemId); } return source; } } 关键的一步,如何生效: String location = "org/springframework/beans/factory/xml/support/customNamespace.properties"; NamespaceHandlerResolver resolver = new DefaultNamespaceHandlerResolver( DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); reader.setNamespaceHandlerResolver(resolver); reader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_XSD); reader.setEntityResolver(new DummySchemaResolver()); reader.loadBeanDefinitions(getResource()); 写一个测试xml文件:
相关的测试方法: publicvoid testSimpleParser() throws Exception { TestBean bean = (TestBean) this.beanFactory.getBean("testBean"); assetTestBean(bean); } publicvoid testSimpleDecorator() throws Exception { TestBean bean = (TestBean) this.beanFactory.getBean("customisedTestBean"); assetTestBean(bean); } publicvoid testProxyingDecorator() throws Exception { ITestBean bean = (ITestBean) this.beanFactory.getBean("debuggingTestBean"); assetTestBean(bean); assertTrue(AopUtils.isAopProxy(bean)); Advisor[] advisors = ((Advised) bean).getAdvisors(); assertEquals("Incorrect number of advisors", 1, advisors.length); assertEquals("Incorrect advice class.", DebugInterceptor.class, advisors[0].getAdvice().getClass()); } publicvoid testChainedDecorators() throws Exception { ITestBean bean = (ITestBean) this.beanFactory.getBean("chainedTestBean"); assetTestBean(bean); assertTrue(AopUtils.isAopProxy(bean)); Advisor[] advisors = ((Advised) bean).getAdvisors(); assertEquals("Incorrect number of advisors", 2, advisors.length); assertEquals("Incorrect advice class.", DebugInterceptor.class, advisors[0].getAdvice().getClass()); assertEquals("Incorrect advice class.", NopInterceptor.class, advisors[1].getAdvice().getClass()); } publicvoid testDecorationViaAttribute() throws Exception { RootBeanDefinition beanDefinition assertEquals("foo", beanDefinition.getAttribute("objectName")); } privatevoid assetTestBean(ITestBean bean) { assertEquals("Invalid name", "Rob Harrop", bean.getName()); assertEquals("Invalid age", 23, bean.getAge()); } |