【Spring】Spring Framework Reference Documentation中文版37

来源:互联网 发布:四川广电网络投诉电话 编辑:程序博客网 时间:2024/06/12 01:33

42. Extensible XML authoring

扩展的XML编写

 

42.1 Introduction

介绍

 

Since version 2.0, Spring has featured a mechanism for schema-based extensions to the basic Spring XML format for defining and configuring beans. This section is devoted to detailing how you would go about writing your own custom XML bean definition parsers and integrating such parsers into the Spring IoC container.

自从版本2.0开始,spring使用了基于schema扩展的策略对于基本的springxml格式化用于定义和配置bean。这一节将讨论你在自定义xmlbean的定义解析和集成的一些细节例如解析到springioc容器中。

 

To facilitate the authoring of configuration files using a schema-aware XML editor, Springs extensible XML configuration mechanism is based on XML Schema. If you are not familiar with Springs current XML configuration extensions that come with the standard Spring distribution, please first read the appendix entitled???.

对于配置授权文件使用schemaxml编辑器,spring扩展的xml配置策略是基于xmlschema的。如果你不熟悉spring当前的xml配置扩展对于spring现有的发行版本,请先阅读整个附录??

 

Creating new XML configuration extensions can be done by following these (relatively) simple steps:

创建一个新的xml配置扩展可以通过下面的简单的步骤:

 

    Authoring an XML schema to describe your custom element(s).

编写xmlschema来描述你自定义的元素。

    Coding a custom NamespaceHandler implementation (this is an easy step, dont worry).

编码一个自定义的NamespaceHandler实现(这是一个简单的步骤,不用担心)

    Coding one or more BeanDefinitionParser implementations (this is where the real work is done).

编码一个或多个BeanDefinitionParser实现(就是你实际实现逻辑的位置)

    Registering the above artifacts with Spring (this too is an easy step).

注册上面的artifactsspring(这也是一个简单的步骤)

 

What follows is a description of each of these steps. For the example, we will create an XML extension (a custom XML element) that allows us to configure objects of the type SimpleDateFormat (from the java.text package) in an easy manner. When we are done, we will be able to define bean definitions of type SimpleDateFormat like this:

下面是每个步骤的描述。例如,我们将创建一个xml的扩展(一个自定义的xml元素)允许我们来配置SimpleDateFormat类型的object(来自java.text包中)是一个简单的方式。当我们完成之后,我们将可以定义SimpleDateFormat类型的bean如下:

 

<myns:dateformat id="dateFormat"

    pattern="yyyy-MM-dd HH:mm"

    lenient="true"/>

 

(Dont worry about the fact that this example is very simple; much more detailed examples follow afterwards. The intent in this first simple example is to walk you through the basic steps involved.)

(不要担心这个例子过于简单,后面还有很多的案例。第一个简单的案例的目的是完成基本步骤的调用。)

 

42.2 Authoring the schema

编写schema

 

Creating an XML configuration extension for use with Springs IoC container starts with authoring an XML Schema to describe the extension. What follows is the schema well use to configure SimpleDateFormat objects.

创建一个xml配置扩展用于使用springIOC容器开始编写一个xmlschema来描述扩展。下面的schema我们将使用来配置SimpleDateFormatobject

 

<!-- myns.xsd (inside package org/springframework/samples/xml) -->

 

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

<xsd:schema xmlns="http://www.mycompany.com/schema/myns"

        xmlns:xsd="http://www.w3.org/2001/XMLSchema"

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

        targetNamespace="http://www.mycompany.com/schema/myns"

        elementFormDefault="qualified"

        attributeFormDefault="unqualified">

 

    <xsd:import namespace="http://www.springframework.org/schema/beans"/>

 

    <xsd:element name="dateformat">

        <xsd:complexType>

            <xsd:complexContent>

                <xsd:extension base="beans:identifiedType">

                    <xsd:attribute name="lenient" type="xsd:boolean"/>

                    <xsd:attribute name="pattern" type="xsd:string" use="required"/>

                </xsd:extension>

            </xsd:complexContent>

        </xsd:complexType>

    </xsd:element>

</xsd:schema>

 

(The emphasized line contains an extension base for all tags that will be identifiable (meaning they have an id attribute that will be used as the bean identifier in the container). We are able to use this attribute because we imported the Spring-provided 'beans' namespace.)

(强调的行中包含了一个扩展用于所有的标签将可以被辨认(意味着他们有id属性将被使用作为bean的标识符在容器中)。我们可以使用这个属性因为我们引入了spring提供的beans的命名空间。)

 

The above schema will be used to configure SimpleDateFormat objects, directly in an XML application context file using the <myns:dateformat/> element.

上面的schema将被使用来配置SimpleDateFormatobject,直接在xml的应用上下文文件中使用<myns:dateformat/>元素。

 

<myns:dateformat id="dateFormat"

    pattern="yyyy-MM-dd HH:mm"

    lenient="true"/>

 

Note that after weve created the infrastructure classes, the above snippet of XML will essentially be exactly the same as the following XML snippet. In other words, were just creating a bean in the container, identified by the name 'dateFormat' of type SimpleDateFormat, with a couple of properties set.

注意在我们创建基础类之后,上面的xml片段将和下面的xml片段是相似的。换句话说,我们只是创建了一个在容器中的bean,通过SimpleDateFormat类型的dateFormat名字来定义,使用一些属性的集合。

 

<bean id="dateFormat" class="java.text.SimpleDateFormat">

    <constructor-arg value="yyyy-HH-dd HH:mm"/>

    <property name="lenient" value="true"/>

</bean>

 

[Note]

注意

 

The schema-based approach to creating configuration format allows for tight integration with an IDE that has a schema-aware XML editor. Using a properly authored schema, you can use autocompletion to have a user choose between several configuration options defined in the enumeration.

基于schema的方式来创建一个配置格式允许简化配置使用IDE因为schemaxml编辑器。使用一个适当的schema,你可以使用自动完成对于用户选择一些配置定义在配置中。

 

42.3 Coding a NamespaceHandler

编写一个NamespaceHandler

 

In addition to the schema, we need a NamespaceHandler that will parse all elements of this specific namespace Spring encounters while parsing configuration files. The NamespaceHandler should in our case take care of the parsing of the myns:dateformat element.

此外对于schema,我们需要一个NamespaceHandler来解析所有spring在配置文件中发现的指定命名空间中的元素。NamespaceHandler在我们的例子中解析myns:dateformat元素。

 

The NamespaceHandler interface is pretty simple in that it features just three methods:

NamespaceHandler接口是十分简单的并且包含三个方法:

 

    init() - allows for initialization of the NamespaceHandler and will be called by Spring before the handler is used

init————允许初始化NamespaceHandler并且将被spring调用在处理器被使用之前。

    BeanDefinition parse(Element, ParserContext) - called when Spring encounters a top-level element (not nested inside a bean definition or a different namespace). This method can register bean definitions itself and/or return a bean definition.

BeanDefinition parse(Element, ParserContext)————当spring解析到底层元素时被调用(没有内置在bean的定义中或另一个命名空间)。这个方法可以注册bean的定义本身或返回一个bean的定义。

    BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext) - called when Spring encounters an attribute or nested element of a different namespace. The decoration of one or more bean definitions is used for example with theout-of-the-box scopes Spring 2.0 supports. Well start by highlighting a simple example, without using decoration, after which we will show decoration in a somewhat more advanced example.

BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext)————spring解析一个属性或不同命名空间的内置元素时被调用。一个或多个bean定义的描述被使用在spring2.0支持中。我们将使用一个简单的例子,不需要使用描述,在我们展示一个更加高级的例子之后。

 

Although it is perfectly possible to code your own NamespaceHandler for the entire namespace (and hence provide code that parses each and every element in the namespace), it is often the case that each top-level XML element in a Spring XML configuration file results in a single bean definition (as in our case, where a single <myns:dateformat/> element results in a single SimpleDateFormat bean definition). Spring features a number of convenience classes that support this scenario. In this example, well make use the NamespaceHandlerSupport class:

尽管对于你的代码有你自己的NamespaceHandler用于整个命名空间(并且提供代码来解析每一个命名空间中的元素),对于每个springxml配置文件中的顶层元素在一个bean的定义中(在我们的例子中,一个简单的<myns:dateformat/>元素返回一个简单的SimpleDateFormatbean的定义)。spring的特性对于一些方便的类来支持这些场景。在这个例子中,我们将会使用NamespaceHandlerSupport类。

 

package org.springframework.samples.xml;

 

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

 

public class MyNamespaceHandler extends NamespaceHandlerSupport {

 

    public void init() {

        registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());

    }

 

}

 

The observant reader will notice that there isnt actually a whole lot of parsing logic in this class. Indeed…​the NamespaceHandlerSupport class has a built in notion of delegation. It supports the registration of any number of BeanDefinitionParser instances, to which it will delegate to when it needs to parse an element in its namespace. This clean separation of concerns allows a NamespaceHandler to handle the orchestration of the parsing of all of the custom elements in its namespace, while delegating to BeanDefinitionParsers to do the grunt work of the XML parsing; this means that each BeanDefinitionParser will contain just the logic for parsing a single custom element, as we can see in the next step

善于观察的读者将意识到他并且不是这个的解析逻辑在这个类中。作为替代,NamespaceHandlerSupport类有内置的代表方式。他支持注册一定数量的BeanDefinitionParser实例,将被委托来解析命名空间中的元素。这些分开的逻辑允许NamespaceHandler来处理解析每一个自定义元素在命名空间中的集合,委托给BeanDefinitionParsers来处理xml的解析工作;这意味着每个BeanDefinitionParser将包含解析单个自定义元素的逻辑,我们在下一步中就能看到。

 

42.4 BeanDefinitionParser

 

A BeanDefinitionParser will be used if the NamespaceHandler encounters an XML element of the type that has been mapped to the specific bean definition parser (which is 'dateformat' in this case). In other words, the BeanDefinitionParser is responsible for parsing one distinct top-level XML element defined in the schema. In the parser, well have access to the XML element (and thus its subelements too) so that we can parse our custom XML content, as can be seen in the following example:

BeanDefinitionParser将被使用如果NamespaceHandler处理一个xml元素来匹配指定的bean定义解析器(在这个例子中是dateformat类型)。换句话说,BeanDefinitionParser用于接卸每个单独的定义xml元素在schema中。在解析器中,我们将访问xml元素(并且和这些子元素)因此我们可以解析我们自定义的xml元素,因此可以被看到下面的例子:

 

package org.springframework.samples.xml;

 

import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;

import org.springframework.util.StringUtils;

import org.w3c.dom.Element;

 

import java.text.SimpleDateFormat;

 

public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 1

 

    protected Class getBeanClass(Element element) {

        return SimpleDateFormat.class; 2

    }

 

    protected void doParse(Element element, BeanDefinitionBuilder bean) {

        // this will never be null since the schema explicitly requires that a value be supplied

        String pattern = element.getAttribute("pattern");

        bean.addConstructorArg(pattern);

 

        // this however is an optional property

        String lenient = element.getAttribute("lenient");

        if (StringUtils.hasText(lenient)) {

            bean.addPropertyValue("lenient", Boolean.valueOf(lenient));

        }

    }

 

}

 

1 We use the Spring-provided AbstractSingleBeanDefinitionParser to handle a lot of the basic grunt work of creating a single BeanDefinition.

我们使用spring提供领导AbstractSingleBeanDefinitionParser来处理基本的逻辑有关创建单一的BeanDefinition

 

2 We supply the AbstractSingleBeanDefinitionParser superclass with the type that our single BeanDefinition will represent.

我们应用AbstractSingleBeanDefinitionParser超类使用我们的单一的BeanDefinition的类型。

 

In this simple case, this is all that we need to do. The creation of our single BeanDefinition is handled by the AbstractSingleBeanDefinitionParser superclass, as is the extraction and setting of the bean definitions unique identifier.

在这个简单的例子中,我们需要这么做。单一的BeanDefinition的创建被处理通过AbstractSingleBeanDefinitionParser超类,因此抽取和设置bean的定义是唯一的标识符。

 

42.5 Registering the handler and the schema

注册处理器和schema

 

The coding is finished! All that remains to be done is to somehow make the Spring XML parsing infrastructure aware of our custom element; we do this by registering our custom namespaceHandler and custom XSD file in two special purpose properties files. These properties files are both placed in a 'META-INF' directory in your application, and can, for example, be distributed alongside your binary classes in a JAR file. The Spring XML parsing infrastructure will automatically pick up your new extension by consuming these special properties files, the formats of which are detailed below.

代码已经完成了。所有保留的部分已经做完了有关展示springxml的解析结构对于我们自定义的元素;我们通过注册我们自定义的namespaceHandler和自定义的xsd文件制定两个特定属性文件。这些属性文件放置在你应用的'META-INF'目录中,并且例如,可以独立于你在JAR文件中的classspirngxml解析架构将自动使用你的新的扩展通过处理这些特定的属性文件以及下面定义的格式。

 

42.5.1 'META-INF/spring.handlers'

 

The properties file called 'spring.handlers' contains a mapping of XML Schema URIs to namespace handler classes. So for our example, we need to write the following:

属性名字为'spring.handlers'包含xmlschemaURI到命名空间处理器类的匹配关系。因此在我们的例子中,我们需要书写如下:

 

http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler

 

(The ':' character is a valid delimiter in the Java properties format, and so the ':' character in the URI needs to be escaped with a backslash.)

(冒号字符是一个合法的分隔符在Java的属性格式中,因此冒号在URL需要被转义编码。)

 

The first part (the key) of the key-value pair is the URI associated with your custom namespace extension, and needs to match exactly the value of the 'targetNamespace' attribute as specified in your custom XSD schema.

第一部分(键)对于键值对是URI匹配你自定义的命名空间扩展,并且需要匹配'targetNamespace'属性的值定义在你自定义的xsdschema中。

 

42.5.2 'META-INF/spring.schemas'

 

The properties file called 'spring.schemas' contains a mapping of XML Schema locations (referred to along with the schema declaration in XML files that use the schema as part of the 'xsi:schemaLocation' attribute) to classpath resources. This file is needed to prevent Spring from absolutely having to use a default EntityResolver that requires Internet access to retrieve the schema file. If you specify the mapping in this properties file, Spring will search for the schema on the classpath (in this case 'myns.xsd' in the 'org.springframework.samples.xml' package):

属性文件名字为'spring.schemas'包含了匹配对于xmlschema的位置(应用定义在xml文件中的schema的定义使用schema作为'xsi:schemaLocation'属性的一部分)以及classpath中的资源。这个文件需要阻止spring使用绝对的默认的EntityResolver及要求网络访问来接收schema文件。如果你定义了匹配属性文件,spring将需找schemaclasspath中(在这个例子中是myns.xsd'org.springframework.samples.xml'包中):

 

http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd

 

The upshot of this is that you are encouraged to deploy your XSD file(s) right alongside the NamespaceHandler and BeanDefinitionParser classes on the classpath.

这个结局是你需要正确的处理你的xsd文件使用NamespaceHandlerBeanDefinitionParser类在你的classpath中。

 

42.6 Using a custom extension in your Spring XML configuration

使用自定义的扩展在你的springxml配置中

 

Using a custom extension that you yourself have implemented is no different from using one of the 'custom' extensions that Spring provides straight out of the box. Find below an example of using the custom <dateformat/> element developed in the previous steps in a Spring XML configuration file.

使用一个自定义的扩展对于你来说需要实现不管是使用自定义的spring提供的扩展还是spring直接提供的。下面的例子使用的自定义的<dateformat/>元素部署在之前步骤中springxml的配置文件中。

 

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

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

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

    xmlns:myns="http://www.mycompany.com/schema/myns"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">

 

    <!-- as a top-level bean -->

    <myns:dateformat id="defaultDateFormat" pattern="yyyy-MM-dd HH:mm" lenient="true"/>

 

    <bean id="jobDetailTemplate" abstract="true">

        <property name="dateFormat">

            <!-- as an inner bean -->

            <myns:dateformat pattern="HH:mm MM-dd-yyyy"/>

        </property>

    </bean>

 

</beans>

 

42.7 Meatier examples

 

Find below some much meatier examples of custom XML extensions.

下面是metier的例子有关自定义的xml扩展。

 

42.7.1 Nesting custom tags within custom tags

内置的自定义标签使用自定义的标签

 

This example illustrates how you might go about writing the various artifacts required to satisfy a target of the following configuration:

这个例子展示了你使用不同的artifacts对于下面的配置:

 

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

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

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

    xmlns:foo="http://www.foo.com/schema/component"

    xsi:schemaLocation="

        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.foo.com/schema/component http://www.foo.com/schema/component/component.xsd">

 

    <foo:component id="bionic-family" name="Bionic-1">

        <foo:component name="Mother-1">

            <foo:component name="Karate-1"/>

            <foo:component name="Sport-1"/>

        </foo:component>

        <foo:component name="Rock-1"/>

    </foo:component>

 

</beans>

 

The above configuration actually nests custom extensions within each other. The class that is actually configured by the above <foo:component/> element is the Component class (shown directly below). Notice how the Component class does not expose a setter method for the 'components' property; this makes it hard (or rather impossible) to configure a bean definition for the Component class using setter injection.

上面的配置实际上内置了自定义的扩展。上面的<foo:component/>元素配置的类是Component类(直接展示如下)。注意Component类没有暴露设置方法对于components属性;这使得很难(几乎不可能)来配置一个bean的定义对于COmponent的类使用设置的注入方式。

 

package com.foo;

 

import java.util.ArrayList;

import java.util.List;

 

public class Component {

 

    private String name;

    private List<Component> components = new ArrayList<Component> ();

 

    // mmm, there is no setter method for the 'components'

    public void addComponent(Component component) {

        this.components.add(component);

    }

 

    public List<Component> getComponents() {

        return components;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

}

 

The typical solution to this issue is to create a custom FactoryBean that exposes a setter property for the 'components' property.

典型的解决方案是创建一个自定义的FactoryBean来暴露一个设置属性对于components属性。

 

package com.foo;

 

import org.springframework.beans.factory.FactoryBean;

 

import java.util.List;

 

public class ComponentFactoryBean implements FactoryBean<Component> {

 

    private Component parent;

    private List<Component> children;

 

    public void setParent(Component parent) {

        this.parent = parent;

    }

 

    public void setChildren(List<Component> children) {

        this.children = children;

    }

 

    public Component getObject() throws Exception {

        if (this.children != null && this.children.size() > 0) {

            for (Component child : children) {

                this.parent.addComponent(child);

            }

        }

        return this.parent;

    }

 

    public Class<Component> getObjectType() {

        return Component.class;

    }

 

    public boolean isSingleton() {

        return true;

    }

 

}

 

This is all very well, and does work nicely, but exposes a lot of Spring plumbing to the end user. What we are going to do is write a custom extension that hides away all of this Spring plumbing. If we stick to the steps described previously, well start off by creating the XSD schema to define the structure of our custom tag.

这是很好的可以工作的,但是暴露了很多spring的部分给终端用户。我们书写的自定义扩展应该隐藏所有的spring的内置内容。如果我们按照之前的步骤,我们需要开始创建xsdschema来定义我们自定义标签的结构。

 

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

 

<xsd:schema xmlns="http://www.foo.com/schema/component"

        xmlns:xsd="http://www.w3.org/2001/XMLSchema"

        targetNamespace="http://www.foo.com/schema/component"

        elementFormDefault="qualified"

        attributeFormDefault="unqualified">

 

    <xsd:element name="component">

        <xsd:complexType>

            <xsd:choice minOccurs="0" maxOccurs="unbounded">

                <xsd:element ref="component"/>

            </xsd:choice>

            <xsd:attribute name="id" type="xsd:ID"/>

            <xsd:attribute name="name" use="required" type="xsd:string"/>

        </xsd:complexType>

    </xsd:element>

 

</xsd:schema>

 

Well then create a custom NamespaceHandler.

我们将创建一个自定义的NamespaceHandler

 

package com.foo;

 

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

 

public class ComponentNamespaceHandler extends NamespaceHandlerSupport {

 

    public void init() {

        registerBeanDefinitionParser("component", new ComponentBeanDefinitionParser());

    }

 

}

 

Next up is the custom BeanDefinitionParser. Remember that what we are creating is a BeanDefinition describing a ComponentFactoryBean.

下一步对于自定义的BeanDefinitionParser。记住我们创建的是一个BeanDefinition描述了一个ComponentFactoryBean

 

package com.foo;

 

import org.springframework.beans.factory.config.BeanDefinition;

import org.springframework.beans.factory.support.AbstractBeanDefinition;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import org.springframework.beans.factory.support.ManagedList;

import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;

import org.springframework.beans.factory.xml.ParserContext;

import org.springframework.util.xml.DomUtils;

import org.w3c.dom.Element;

 

import java.util.List;

 

public class ComponentBeanDefinitionParser extends AbstractBeanDefinitionParser {

 

    protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {

        return parseComponentElement(element);

    }

 

    private static AbstractBeanDefinition parseComponentElement(Element element) {

        BeanDefinitionBuilder factory = BeanDefinitionBuilder.rootBeanDefinition(ComponentFactoryBean.class);

        factory.addPropertyValue("parent", parseComponent(element));

 

        List<Element> childElements = DomUtils.getChildElementsByTagName(element, "component");

        if (childElements != null && childElements.size() > 0) {

            parseChildComponents(childElements, factory);

        }

 

        return factory.getBeanDefinition();

    }

 

    private static BeanDefinition parseComponent(Element element) {

        BeanDefinitionBuilder component = BeanDefinitionBuilder.rootBeanDefinition(Component.class);

        component.addPropertyValue("name", element.getAttribute("name"));

        return component.getBeanDefinition();

    }

 

    private static void parseChildComponents(List<Element> childElements, BeanDefinitionBuilder factory) {

        ManagedList<BeanDefinition> children = new ManagedList<BeanDefinition>(childElements.size());

        for (Element element : childElements) {

            children.add(parseComponentElement(element));

        }

        factory.addPropertyValue("children", children);

    }

 

}

 

Lastly, the various artifacts need to be registered with the Spring XML infrastructure.

最后,不同artifacts需要被注册使用springxml结构。

 

# in 'META-INF/spring.handlers'

http\://www.foo.com/schema/component=com.foo.ComponentNamespaceHandler

 

# in 'META-INF/spring.schemas'

http\://www.foo.com/schema/component/component.xsd=com/foo/component.xsd

 

42.7.2 Custom attributes on 'normal' elements

自定义属性对于normal元素

 

Writing your own custom parser and the associated artifacts isnt hard, but sometimes it is not the right thing to do. Consider the scenario where you need to add metadata to already existing bean definitions. In this case you certainly dont want to have to go off and write your own entire custom extension; rather you just want to add an additional attribute to the existing bean definition element.

使用你自定义的解析器和相关的artifacts不是困难的,但是有时他不是正确的方式。考虑这样的场景,你需要添加一个元数据对于已有的bean的定义。在这个例子中你不需要书写你自己的整个自定义扩展;你只是添加一个额外的属性对于已有的bean定义元素。

 

By way of another example, lets say that the service class that you are defining a bean definition for a service object that will (unknown to it) be accessing a clustered JCache, and you want to ensure that the named JCache instance is eagerly started within the surrounding cluster:

对于另一个例子,我们呢看到你定义的服务类定义了一个bean的定义用于服务object(对其不知)可以被一个集群的JCache访问,并且你保证名字为JCache的实例是使用下面的集群开始的:

 

<bean id="checkingAccountService" class="com.foo.DefaultCheckingAccountService"

        jcache:cache-name="checking.account">

    <!-- other dependencies here... -->

</bean>

 

What we are going to do here is create another BeanDefinition when the 'jcache:cache-name' attribute is parsed; this BeanDefinition will then initialize the named JCache for us. We will also modify the existing BeanDefinition for the 'checkingAccountService' so that it will have a dependency on this new JCache-initializing BeanDefinition.

我们需要做的是创建另一个BeanDefinition'jcache:cache-name'属性被解析的时候,这个BeanDefinition将初始化JCache。我们将修改已有的BeanDefinition用于'checkingAccountService'因此他将会依赖心的JCache的初始化BeanDefinition

 

package com.foo;

 

public class JCacheInitializer {

 

    private String name;

 

    public JCacheInitializer(String name) {

        this.name = name;

    }

 

    public void initialize() {

        // lots of JCache API calls to initialize the named cache...

    }

 

}

 

Now onto the custom extension. Firstly, the authoring of the XSD schema describing the custom attribute (quite easy in this case).

现在对于自定义扩展。首先,XSD的授权描述了自定义属性(在这个例子中是很简单的)。

 

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

 

<xsd:schema xmlns="http://www.foo.com/schema/jcache"

        xmlns:xsd="http://www.w3.org/2001/XMLSchema"

        targetNamespace="http://www.foo.com/schema/jcache"

        elementFormDefault="qualified">

 

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

 

</xsd:schema>

 

Next, the associated NamespaceHandler.

后面是相关的NamespaceHandler

 

package com.foo;

 

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

 

public class JCacheNamespaceHandler extends NamespaceHandlerSupport {

 

    public void init() {

        super.registerBeanDefinitionDecoratorForAttribute("cache-name",

            new JCacheInitializingBeanDefinitionDecorator());

    }

 

}

 

Next, the parser. Note that in this case, because we are going to be parsing an XML attribute, we write a BeanDefinitionDecorator rather than a BeanDefinitionParser.

后面是解析器。注意在这个例子中,因为我们希望解析一个xml属性,我们需要提供一个BeanDefinitionDecorator而不是BeanDefinitionParser

 

package com.foo;

 

import org.springframework.beans.factory.config.BeanDefinitionHolder;

import org.springframework.beans.factory.support.AbstractBeanDefinition;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;

import org.springframework.beans.factory.xml.BeanDefinitionDecorator;

import org.springframework.beans.factory.xml.ParserContext;

import org.w3c.dom.Attr;

import org.w3c.dom.Node;

 

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

 

public class JCacheInitializingBeanDefinitionDecorator implements BeanDefinitionDecorator {

 

    private static final String[] EMPTY_STRING_ARRAY = new String[0];

 

    public BeanDefinitionHolder decorate(Node source, BeanDefinitionHolder holder,

            ParserContext ctx) {

        String initializerBeanName = registerJCacheInitializer(source, ctx);

        createDependencyOnJCacheInitializer(holder, initializerBeanName);

        return holder;

    }

 

    private void createDependencyOnJCacheInitializer(BeanDefinitionHolder holder,

            String initializerBeanName) {

        AbstractBeanDefinition definition = ((AbstractBeanDefinition) holder.getBeanDefinition());

        String[] dependsOn = definition.getDependsOn();

        if (dependsOn == null) {

            dependsOn = new String[]{initializerBeanName};

        } else {

            List dependencies = new ArrayList(Arrays.asList(dependsOn));

            dependencies.add(initializerBeanName);

            dependsOn = (String[]) dependencies.toArray(EMPTY_STRING_ARRAY);

        }

        definition.setDependsOn(dependsOn);

    }

 

    private String registerJCacheInitializer(Node source, ParserContext ctx) {

        String cacheName = ((Attr) source).getValue();

        String beanName = cacheName + "-initializer";

        if (!ctx.getRegistry().containsBeanDefinition(beanName)) {

            BeanDefinitionBuilder initializer = BeanDefinitionBuilder.rootBeanDefinition(JCacheInitializer.class);

            initializer.addConstructorArg(cacheName);

            ctx.getRegistry().registerBeanDefinition(beanName, initializer.getBeanDefinition());

        }

        return beanName;

    }

 

}

 

Lastly, the various artifacts need to be registered with the Spring XML infrastructure.

最后,不同的artifacts需要被注册使用springxml架构。

 

# in 'META-INF/spring.handlers'

http\://www.foo.com/schema/jcache=com.foo.JCacheNamespaceHandler

 

# in 'META-INF/spring.schemas'

http\://www.foo.com/schema/jcache/jcache.xsd=com/foo/jcache.xsd

 

42.8 Further Resources

更多的资源

 

Find below links to further resources concerning XML Schema and the extensible XML support described in this chapter.

下面的链接指向更多的资源有关xmlschema和扩展的xml支持描述在这些章节中。

 

    The XML Schema Part 1: Structures Second Edition

xmlschema部分一:结构第二版

    The XML Schema Part 2: Datatypes Second Edition

xmlschema部分二:数据类型第二版

 

 

阅读全文
0 0
原创粉丝点击