论坛首页 Java企业应用论坛

关于spring 2.0自定义xml 标记 (二 如何实现)

浏览 14427 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-10-27  
看了spring test 用例,其实实现这一功能还算比较简单,主要分以下的步骤,具体的实例可以去参考spring 自带的testcase

首先定义相关xsd文件,用于验证相应的行为:

主要增加了4个自定义元素和1个属性:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

    <xsd:schema xmlns="http://www.springframework.org/schema/beans/test"
                        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                        targetNamespace="http://www.springframework.org/schema/beans/test"
                        elementFormDefault="qualified">

    <xsd:element name="testBean">
        <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string" use="required" form="unqualified"/>
            <xsd:attribute name="name" type="xsd:string" use="required" form="unqualified"/>
            <xsd:attribute name="age" type="xsd:integer" use="required" form="unqualified"/>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="set">
        <xsd:complexType>
            <xsd:attribute name="name" type="xsd:string" use="required" form="unqualified"/>
            <xsd:attribute name="age" type="xsd:integer" use="required" form="unqualified"/>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="debug"/>
    <xsd:element name="nop"/>

    <xsd:attribute name="object-name" type="xsd:string"/>

</xsd:schema>

接着定义handler映射文件:customNamespace.properties

http\://www.springframework.org/schema/beans/test=org.springframework.beans.factory.xml.support.TestNamespaceHandler

定义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 =
                                  new ClassPathResource("org/springframework/beans/factory/xml/support/spring-test.xsd");

              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(
                                                                                                                        getClass().getClassLoader(), location);

         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文件:

<?xmlversion="1.0"encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

            xmlns:test="http://www.springframework.org/schema/beans/test"

            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

       http://www.springframework.org/schema/beans/testhttp://www.springframework.org/schema/beans/factory/xml/support/spring-test.xsd">

    <test:testBeanid="testBean"name="Rob Harrop"age="23"/>

    <beanid="customisedTestBean"class="org.springframework.beans.TestBean">

       <test:setname="Rob Harrop"age="23"/>

    </bean>

    <beanid="debuggingTestBean"class="org.springframework.beans.TestBean">

       <test:debug/>

       <propertyname="name"value="Rob Harrop"/>

       <propertyname="age"value="23"/>

    </bean>

    <beanid="chainedTestBean"class="org.springframework.beans.TestBean">

       <test:debug/>

       <test:nop/>

       <propertyname="name"value="Rob Harrop"/>

       <propertyname="age"value="23"/>

    </bean>

    <beanid="decorateWithAttribute"class="org.springframework.beans.TestBean"test:object-name="foo"/>

</beans>

相关的测试方法:

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
                           = (RootBeanDefinition)this.beanFactory.getBeanDefinition("decorateWithAttribute");

       assertEquals("foo", beanDefinition.getAttribute("objectName"));

    }

    privatevoid assetTestBean(ITestBean bean) {

       assertEquals("Invalid name", "Rob Harrop", bean.getName());

       assertEquals("Invalid age", 23, bean.getAge());

    }
   发表时间:2006-10-29  
   我初步觉得这种功能基本上实用性不大,但是作为一个框架,提供这种功能,在宣传上就又多了一个噱头。
0 请登录后投票
   发表时间:2006-10-29  
spring的文档说得很清楚,这个功能是给第三方框架开发自己的schema用的,如果各个第三方框架都像<aop:> <tx:>那样提供简写,我们的配置文件就会简单一点。
0 请登录后投票
   发表时间:2006-10-30  
江南白衣 写道
spring的文档说得很清楚,这个功能是给第三方框架开发自己的schema用的,如果各个第三方框架都像<aop:> <tx:>那样提供简写,我们的配置文件就会简单一点。

acegi适合这样做,能节约不少字数
compass已经这么做的
0 请登录后投票
   发表时间:2006-10-30  
这是一个非常重要的特性。它使得spring可以成为DSL的框架,定义自己的语法。看看springRichClient中menu的定义多么复杂就知道多么需要这个特性了。死的框架是没有什么意思的,只有可以定义语法的元级框架才是王道。rails是很不错的,但是它只是分析清理和剪裁了需求的结果,真正的惊喜是ruby和无处不在的DSL思想。这点和spring1.2与spring2的区别很象。
0 请登录后投票
   发表时间:2006-10-30  
myace 写道
这是一个非常重要的特性。它使得spring可以成为DSL的框架,定义自己的语法。看看springRichClient中menu的定义多么复杂就知道多么需要这个特性了。死的框架是没有什么意思的,只有可以定义语法的元级框架才是王道。rails是很不错的,但是它只是分析清理和剪裁了需求的结果,真正的惊喜是ruby和无处不在的DSL思想。这点和spring1.2与spring2的区别很象。

有道理
0 请登录后投票
   发表时间:2007-08-28  
对于第三方是非常的有用的,比如dwr
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics