Live2D

spring官网在线学习文档翻译9

9. Appendix(附录)

9.1. XML Schemas(xml模式)

This part of the appendix lists XML schemas related to the core container.

  • 附录的这一部分列出了与核心容器相关的XML模式。

9.1.1. The util schema(实效的模式)

As the name implies, the util tags deal with common, utility configuration issues, such as configuring collections, referencing constants, and suchlike. To use the tags in the util schema, you need to have the following preamble at the top of your Spring XML configuration file; the text in the snippet below references the correct schema so that the tags in the util namespace are available to you.

  • 顾名思义,util标记处理常见的实用程序配置问题,例如配置集合、引用常量等等。要在util模式中使用标记,您需要在Spring XML配置文件的顶部有以下序言;下面的代码片段中的文本引用了正确的模式,以便您可以使用util名称空间中的标记。
<?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:util="http://www.springframework.org/schema/util" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- bean definitions here -->

</beans>
util:constant/

Before…

<bean id="..." class="...">
    <property name="isolation">
        <bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
                class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
    </property>
</bean>

The above configuration uses a Spring FactoryBean implementation, the FieldRetrievingFactoryBean, to set the value of the isolation property on a bean to the value of the java.sql.Connection.TRANSACTION_SERIALIZABLE constant. This is all well and good, but it is a tad verbose and (unnecessarily) exposes Spring’s internal plumbing to the end user.

  • 上面的配置使用Spring FactoryBean实现FieldRetrievingFactoryBean将bean上的隔离属性的值设置为java.sql.Connection的值。TRANSACTION_SERIALIZABLE常数。这一切都很好,但是它有点冗长,并且(不必要地)向最终用户暴露了Spring的内部管道。

The following XML Schema-based version is more concise and clearly expresses the developer’s intent ('inject this constant value'), and it just reads better.

  • 下面的基于XML模式的版本更简洁,更清楚地表达了开发人员的意图(‘注入这个常数值’),而且可读性更好。
<bean id="..." class="...">
    <property name="isolation">
        <util:constant static-field="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
    </property>
</bean>
Setting a bean property or constructor arg from a field value(从字段值设置bean属性或构造函数参数)

FieldRetrievingFactoryBean is a FactoryBean which retrieves a static or non-static field value. It is typically used for retrieving public static final constants, which may then be used to set a property value or constructor arg for another bean.

  • 从字段值设置bean属性或构造函数参数

    FieldRetrievingFactoryBean是一个获取静态或非静态字段值的FactoryBean。它通常用于检索公共静态最终常数,然后可用于为另一个bean设置属性值或构造函数参数。

Find below an example which shows how a static field is exposed, by using the staticField property:

  • 下面是一个例子,通过使用staticField属性,静态字段是如何暴露的:
<bean id="myField"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
    <property name="staticField" value="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
</bean>

There is also a convenience usage form where the static field is specified as the bean name:

  • 还有一种方便的使用形式,将静态字段指定为bean名:
<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
        class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>

This does mean that there is no longer any choice in what the bean id is (so any other bean that refers to it will also have to use this longer name), but this form is very concise to define, and very convenient to use as an inner bean since the id doesn’t have to be specified for the bean reference:

  • 这并意味着不再有任何选择bean id是什么(任何其他bean,指的是它还必须使用长名),但这种形式非常简洁的定义,和非常方便的使用作为一个内在bean id以来没有指定bean引用:
<bean id="..." class="...">
    <property name="isolation">
        <bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
                class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" />
    </property>
</bean>

It is also possible to access a non-static (instance) field of another bean, as described in the API documentation for the FieldRetrievingFactoryBean class.

  • 还可以访问另一个bean的非静态(实例)字段,如FieldRetrievingFactoryBean类的API文档中所描述的那样。

Injecting enum values into beans as either property or constructor arguments is very easy to do in Spring, in that you don’t actually have to do anything or know anything about the Spring internals (or even about classes such as the FieldRetrievingFactoryBean). Let’s look at an example to see how easy injecting an enum value is; consider this enum:

  • 在Spring中,将enum值作为属性或构造函数参数注入到bean中非常容易,因为您实际上不需要做任何事情,也不需要了解Spring内部的任何事情(甚至不需要了解诸如FieldRetrievingFactoryBean之类的类)。让我们看一个例子,看看注入枚举值是多么容易;考虑一下这个枚举:
package javax.persistence;

public enum PersistenceContextType {

    TRANSACTION,
    EXTENDED
}

Now consider a setter of type PersistenceContextType:

  • 现在考虑一个类型为PersistenceContextType的setter:
package example;

public class Client {

    private PersistenceContextType persistenceContextType;

    public void setPersistenceContextType(PersistenceContextType type) {
        this.persistenceContextType = type;
    }
}
  1. and the corresponding bean definition:
    • 以及对应的bean定义:
<bean class="example.Client">
    <property name="persistenceContextType" value="TRANSACTION"/>
</bean>
util:property-path/

Before…

<!-- target bean to be referenced by name -->
<bean id="testBean" class="org.springframework.beans.TestBean" scope="prototype">
    <property name="age" value="10"/>
    <property name="spouse">
        <bean class="org.springframework.beans.TestBean">
            <property name="age" value="11"/>
        </bean>
    </property>
</bean>

<!-- will result in 10, which is the value of property 'age' of bean 'testBean' -->
<bean id="testBean.age" class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>

The above configuration uses a Spring FactoryBean implementation, the PropertyPathFactoryBean, to create a bean (of type int) called testBean.age that has a value equal to the age property of the testBean bean.

  • 上面的配置使用Spring FactoryBean实现PropertyPathFactoryBean来创建一个名为testBean (int类型)的bean。值等于testBean bean的age属性的age。

After…

<!-- target bean to be referenced by name -->
<bean id="testBean" class="org.springframework.beans.TestBean" scope="prototype">
    <property name="age" value="10"/>
    <property name="spouse">
        <bean class="org.springframework.beans.TestBean">
            <property name="age" value="11"/>
        </bean>
    </property>
</bean>

<!-- will result in 10, which is the value of property 'age' of bean 'testBean' -->
<util:property-path id="name" path="testBean.age"/>

The value of the path attribute of the <property-path/> tag follows the form beanName.beanProperty.

  • 标记的path属性的值遵循表单beanName.beanProperty。
Using util:property-path/ to set a bean property or constructor-argument (使用util:property-path/设置bean属性或构造参数)

PropertyPathFactoryBean is a FactoryBean that evaluates a property path on a given target object. The target object can be specified directly or via a bean name. This value may then be used in another bean definition as a property value or constructor argument.

  • PropertyPathFactoryBean是一个FactoryBean,它计算给定目标对象上的属性路径。可以直接指定目标对象,也可以通过bean名称指定。然后,这个值可以作为属性值或构造函数参数在另一个bean定义中使用。

Here’s an example where a path is used against another bean, by name:

  • 这里有一个例子,通过名称对另一个bean使用路径:
// target bean to be referenced by name
<bean id="person" class="org.springframework.beans.TestBean" scope="prototype">
    <property name="age" value="10"/>
    <property name="spouse">
        <bean class="org.springframework.beans.TestBean">
            <property name="age" value="11"/>
        </bean>
    </property>
</bean>

// will result in 11, which is the value of property 'spouse.age' of bean 'person'
<bean id="theAge"
        class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
    <property name="targetBeanName" value="person"/>
    <property name="propertyPath" value="spouse.age"/>
</bean>

In this example, a path is evaluated against an inner bean:

  • 在这个例子中,路径是根据内部bean计算的:
<!-- will result in 12, which is the value of property 'age' of the inner bean -->
<bean id="theAge"
        class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
    <property name="targetObject">
        <bean class="org.springframework.beans.TestBean">
            <property name="age" value="12"/>
        </bean>
    </property>
    <property name="propertyPath" value="age"/>
</bean>

There is also a shortcut form, where the bean name is the property path.

  • 还有一个快捷形式,其中bean名称是属性路径。
<!-- will result in 10, which is the value of property 'age' of bean 'person' -->
<bean id="person.age"
        class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>

This form does mean that there is no choice in the name of the bean. Any reference to it will also have to use the same id, which is the path. Of course, if used as an inner bean, there is no need to refer to it at all:

  • 这种形式确实意味着对bean的名称没有选择。对它的任何引用也必须使用相同的id,即路径。当然,如果作为内部bean使用,根本不需要引用它:
<bean id="..." class="...">
    <property name="age">
        <bean id="person.age"
                class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>
    </property>
</bean>

The result type may be specifically set in the actual definition. This is not necessary for most use cases, but can be of use for some. Please see the Javadocs for more info on this feature.

  • 结果类型可以在实际定义中专门设置。这对于大多数用例来说是不必要的,但是对于某些用例来说是有用的。有关此特性的更多信息,请参阅Javadocs。
util:properties/

Before…

<!-- creates a java.util.Properties instance with values loaded from the supplied location -->
<bean id="jdbcConfiguration" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="location" value="classpath:com/foo/jdbc-production.properties"/>
</bean>

The above configuration uses a Spring FactoryBean implementation, the PropertiesFactoryBean, to instantiate a java.util.Properties instance with values loaded from the supplied Resource location).

  • 上面的配置使用Spring FactoryBean实现PropertiesFactoryBean来实例化java.util。属性实例,其值从提供的资源位置加载)。

After…

<!-- creates a java.util.Properties instance with values loaded from the supplied location -->
<util:properties id="jdbcConfiguration" location="classpath:com/foo/jdbc-production.properties"/>
util:list/

Before…

<!-- creates a java.util.List instance with values loaded from the supplied 'sourceList' -->
<bean id="emails" class="org.springframework.beans.factory.config.ListFactoryBean">
    <property name="sourceList">
        <list>
            <value>pechorin@hero.org</value>
            <value>raskolnikov@slums.org</value>
            <value>stavrogin@gov.org</value>
            <value>porfiry@gov.org</value>
        </list>
    </property>
</bean>

The above configuration uses a Spring FactoryBean implementation, the ListFactoryBean, to create a java.util.List instance initialized with values taken from the supplied sourceList.

  • 上面的配置使用Spring FactoryBean实现ListFactoryBean来创建java.util。使用从提供的源列表中获取的值初始化的列表实例。

After…

<!-- creates a java.util.List instance with the supplied values -->
<util:list id="emails">
    <value>pechorin@hero.org</value>
    <value>raskolnikov@slums.org</value>
    <value>stavrogin@gov.org</value>
    <value>porfiry@gov.org</value>
</util:list>

You can also explicitly control the exact type of List that will be instantiated and populated via the use of the list-class attribute on the <util:list/> element. For example, if we really need a java.util.LinkedList to be instantiated, we could use the following configuration:

  • 您还可以通过使用<util: List />元素上的List -class属性显式地控制将实例化和填充的List的确切类型。例如,如果我们确实需要java.util。要实例化LinkedList,我们可以使用以下配置:
<util:list id="emails" list-class="java.util.LinkedList">
    <value>jackshaftoe@vagabond.org</value>
    <value>eliza@thinkingmanscrumpet.org</value>
    <value>vanhoek@pirate.org</value>
    <value>d'Arcachon@nemesis.org</value>
</util:list>

If no list-class attribute is supplied, a List implementation will be chosen by the container.

  • 如果没有提供List -class属性,容器将选择List实现。
util:map/

Before…

<!-- creates a java.util.Map instance with values loaded from the supplied 'sourceMap' -->
<bean id="emails" class="org.springframework.beans.factory.config.MapFactoryBean">
    <property name="sourceMap">
        <map>
            <entry key="pechorin" value="pechorin@hero.org"/>
            <entry key="raskolnikov" value="raskolnikov@slums.org"/>
            <entry key="stavrogin" value="stavrogin@gov.org"/>
            <entry key="porfiry" value="porfiry@gov.org"/>
        </map>
    </property>
</bean>

The above configuration uses a Spring FactoryBean implementation, the MapFactoryBean, to create a java.util.Map instance initialized with key-value pairs taken from the supplied 'sourceMap'.

  • 上面的配置使用Spring FactoryBean实现MapFactoryBean来创建java.util。使用从提供的“sourceMap”中获取的键-值对初始化的映射实例。

After…

<!-- creates a java.util.Map instance with the supplied key-value pairs -->
<util:map id="emails">
    <entry key="pechorin" value="pechorin@hero.org"/>
    <entry key="raskolnikov" value="raskolnikov@slums.org"/>
    <entry key="stavrogin" value="stavrogin@gov.org"/>
    <entry key="porfiry" value="porfiry@gov.org"/>
</util:map>

You can also explicitly control the exact type of Map that will be instantiated and populated via the use of the 'map-class' attribute on the <util:map/> element. For example, if we really need a java.util.TreeMap to be instantiated, we could use the following configuration:

  • 您还可以通过使用<util: Map />元素上的' Map -class'属性显式地控制将实例化和填充的Map的确切类型。例如,如果我们确实需要java.util。要实例化TreeMap,我们可以使用以下配置:
<util:map id="emails" map-class="java.util.TreeMap">
    <entry key="pechorin" value="pechorin@hero.org"/>
    <entry key="raskolnikov" value="raskolnikov@slums.org"/>
    <entry key="stavrogin" value="stavrogin@gov.org"/>
    <entry key="porfiry" value="porfiry@gov.org"/>
</util:map>

If no 'map-class' attribute is supplied, a Map implementation will be chosen by the container.

  • 如果没有提供“Map -class”属性,容器将选择一个Map实现。
util:set/

Before…

<!-- creates a java.util.Set instance with values loaded from the supplied 'sourceSet' -->
<bean id="emails" class="org.springframework.beans.factory.config.SetFactoryBean">
    <property name="sourceSet">
        <set>
            <value>pechorin@hero.org</value>
            <value>raskolnikov@slums.org</value>
            <value>stavrogin@gov.org</value>
            <value>porfiry@gov.org</value>
        </set>
    </property>
</bean>

The above configuration uses a Spring FactoryBean implementation, the SetFactoryBean, to create a java.util.Set instance initialized with values taken from the supplied 'sourceSet'.

  • 上面的配置使用Spring FactoryBean实现SetFactoryBean来创建java.util。使用从提供的“sourceSet”获取的值设置实例初始化。

After…

<!-- creates a java.util.Set instance with the supplied values -->
<util:set id="emails">
    <value>pechorin@hero.org</value>
    <value>raskolnikov@slums.org</value>
    <value>stavrogin@gov.org</value>
    <value>porfiry@gov.org</value>
</util:set>

You can also explicitly control the exact type of Set that will be instantiated and populated via the use of the 'set-class' attribute on the <util:set/> element. For example, if we really need a java.util.TreeSet to be instantiated, we could use the following configuration:

  • 还可以通过使用<util: Set />元素上的' Set -class'属性显式控制将实例化和填充的Set的确切类型。例如,如果我们确实需要java.util。要实例化TreeSet,我们可以使用以下配置:
<util:set id="emails" set-class="java.util.TreeSet">
    <value>pechorin@hero.org</value>
    <value>raskolnikov@slums.org</value>
    <value>stavrogin@gov.org</value>
    <value>porfiry@gov.org</value>
</util:set>

If no 'set-class' attribute is supplied, a Set implementation will be chosen by the container.

  • 如果没有提供' Set -class'属性,容器将选择Set实现。

9.1.2. The aop schema(aop的模式)

The aop tags deal with configuring all things AOP in Spring: this includes Spring’s own proxy-based AOP framework and Spring’s integration with the AspectJ AOP framework. These tags are comprehensively covered in the chapter entitled Aspect Oriented Programming with Spring.

  • aop标记处理在Spring中配置aop的所有内容:这包括Spring自己的基于代理的aop框架,以及Spring与AspectJ aop框架的集成。这些标签在“用Spring进行面向方面编程”一章中有全面的介绍。

In the interest of completeness, to use the tags in the aop schema, you need to have the following preamble at the top of your Spring XML configuration file; the text in the following snippet references the correct schema so that the tags in the aop namespace are available to you.

  • 出于完整性的考虑,要在aop模式中使用标记,您需要在Spring XML配置文件的顶部有以下序言;下面代码片段中的文本引用了正确的模式,以便aop名称空间中的标记对您可用。
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

</beans>

9.1.3. The context schema(上下文模式)

The context tags deal with ApplicationContext configuration that relates to plumbing - that is, not usually beans that are important to an end-user but rather beans that do a lot of grunt work in Spring, such as BeanfactoryPostProcessors. The following snippet references the correct schema so that the tags in the context namespace are available to you.

  • 上下文标记处理与管道相关的ApplicationContext配置——也就是说,通常不是对终端用户重要的bean,而是在Spring中执行大量繁重工作的bean,如beanfactorypostprocessor。下面的代码片段引用了正确的模式,以便上下文名称空间中的标记对您可用。
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->

</beans>

This element activates the replacement of ${…} placeholders, resolved against the specified properties file (as a Spring resource location). This element is a convenience mechanism that sets up aPropertyPlaceholderConfigurer for you; if you need more control over the PropertyPlaceholderConfigurer, just define one yourself explicitly.

  • 此元素激活替换根据指定属性文件(作为Spring资源位置)解析的${…}占位符。这个元素是一个方便的机制,它为您设置了一个propertyplaceholderconfigurer;如果您需要对PropertyPlaceholderConfigurer进行更多的控制,只需自己显式地定义一个。

Activates the Spring infrastructure for various annotations to be detected in bean classes: Spring’s @Required and @Autowired, as well as JSR 250’s @PostConstruct, @PreDestroy and @Resource (if available), and JPA’s @PersistenceContext and @PersistenceUnit (if available). Alternatively, you can choose to activate the individual BeanPostProcessors for those annotations explicitly.

  • 为在bean类中检测到的各种注释激活Spring基础设施:Spring的@Required和@Autowired,以及JSR 250的@PostConstruct, @PreDestroy和@Resource(如果可用),以及JPA的@PersistenceContext和@PersistenceUnit(如果可用)。或者,您可以选择为这些注释显式地激活单独的beanpostprocessor。
This element does not activate processing of Spring’s @Transactional annotation. Use the `` element for that purpose.
  • 该元素不激活Spring的@Transactional注释的处理。为此,可以使用tx:注释驱动的/元素。

This element is detailed in Annotation-based container configuration.

  • 该元素在基于注释的容器配置中有详细说明。

This element is detailed in Load-time weaving with AspectJ in the Spring Framework.

  • 这个元素在Spring框架的加载时与AspectJ编织中有详细说明。

This element is detailed in Using AspectJ to dependency inject domain objects with Spring.

  • 这个元素在使用AspectJ用Spring依赖注入域对象中有详细说明。

This element is detailed in Configuring annotation based MBean export.

  • 这个元素在配置基于MBean导出的注释中有详细说明。

9.1.4. The beans schema(bean模式)

Last but not least we have the tags in the beans schema. These are the same tags that have been in Spring since the very dawn of the framework. Examples of the various tags in the beans schema are not shown here because they are quite comprehensively covered in Dependencies and configuration in detail (and indeed in that entire chapter).

  • 最后但并非最不重要的是,我们在bean模式中有标记。这些都是自框架诞生之初就存在于Spring中的相同标签。这里没有显示bean模式中各种标记的示例,因为它们在依赖关系和配置中已经得到了非常全面的详细介绍(实际上在整章中都有介绍)。

Note that it is possible to add zero or more key / value pairs to <bean/> XML definitions. What, if anything, is done with this extra metadata is totally up to your own custom logic (and so is typically only of use if you are writing your own custom tags as described in the appendix entitled XML Schema Authoring).

  • 注意,可以向 XML定义添加零个或多个键/值对。用这些额外的元数据做什么(如果有的话)完全取决于您自己的定制逻辑(通常只有在编写自己的定制标记时才有用,如附录XML Schema Authoring所述)。

Find below an example of the <meta/> tag in the context of a surrounding <bean/> (please note that without any logic to interpret it the metadata is effectively useless as-is).

  • 下面是上下文中的标签的示例(请注意,如果没有任何逻辑来解释它,元数据实际上是无用的)。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    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">

    <bean id="foo" class="x.y.Foo">
        <meta key="cacheName" value="foo"/>
        <property name="name" value="Rick"/>
    </bean>

</beans>

In the case of the above example, you would assume that there is some logic that will consume the bean definition and set up some caching infrastructure using the supplied metadata.

  • 在上面的例子中,您可能会假设有一些逻辑将使用bean定义并使用提供的元数据设置一些缓存基础设施。

9.2. XML Schema Authoring(XML Schema编辑)

9.2.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就提供了一种基于模式的机制,用于对基本Spring XML格式进行扩展,以定义和配置bean。本节将详细介绍如何编写自己的定制XML bean定义解析器,以及如何将此类解析器集成到Spring IoC容器中。

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

  • 为了方便使用感知模式的XML编辑器编写配置文件,Spring的可扩展XML配置机制基于XML模式。如果您不熟悉标准Spring发行版附带的Spring当前XML配置扩展,请首先阅读名为[xsd-config]的附录。

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).
    • 编写XML模式来描述定制元素。
  • Coding a custom NamespaceHandler implementation (this is an easy step, don’t 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).
    • 向Spring注册上述构件(这也是一个简单的步骤)。

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类型的对象(来自java)。文本包)在一个简单的方式。完成之后,我们就可以像这样定义SimpleDateFormat类型的bean定义了:
<myns:dateformat id="dateFormat"
    pattern="yyyy-MM-dd HH:mm"
    lenient="true"/>

(Don’t 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.)

  • (不用担心这个例子非常简单;后面会有更详细的示例。第一个简单示例的目的是引导您完成所涉及的基本步骤。)

9.2.2. Authoring the schema(编辑模式)

Creating an XML configuration extension for use with Spring’s IoC container starts with authoring an XML Schema to describe the extension. What follows is the schema we’ll use to configure SimpleDateFormat objects.

  • 要创建一个用于Spring的IoC容器的XML配置扩展,首先要创建一个描述扩展的XML模式。下面是我们将用于配置SimpleDateFormat对象的模式。
<!-- 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提供的“bean”名称空间。)

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

  • 上面的模式将用于配置SimpleDateFormat对象,直接在XML应用程序上下文文件中使用myns:dateformat/元素。
<myns:dateformat id="dateFormat"
    pattern="yyyy-MM-dd HH:mm"
    lenient="true"/>

Note that after we’ve created the infrastructure classes, the above snippet of XML will essentially be exactly the same as the following XML snippet. In other words, we’re 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>
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.
  • 创建配置格式的基于模式的方法允许与具有模式感知XML编辑器的IDE紧密集成。使用正确编写的模式,可以使用自动完成让用户在枚举中定义的几个配置选项中进行选择。

9.2.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.

  • 除了模式之外,我们还需要一个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 the out-of-the-box scopes Spring supports. We’ll start by highlighting a simple example, without using decoration, after which we will show decoration in a somewhat more advanced example.
    • BeanDefinitionHolder修饰(节点、BeanDefinitionHolder、ParserContext)——当Spring遇到不同名称空间的属性或嵌套元素时调用。例如,使用Spring支持的开箱即用范围来装饰一个或多个bean定义。我们将从突出显示一个不使用装饰的简单示例开始,之后我们将在一个更高级的示例中展示装饰。

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, we’ll make use the NamespaceHandlerSupport class:

  • 尽管是完全可能的代码自己的NamespaceHandler整个名称空间(因此提供代码解析每一个元素的名称空间),通常情况下,每个顶级XML元素在Spring XML配置文件的结果在一个bean定义(在我们的例子中,一个< myns: dateformat / >元素的结果在一个SimpleDateFormat bean定义)。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 isn’t 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处理其名称空间中所有定制元素解析的编排,同时委托beandefinitionparser来完成XML解析的繁琐工作;这意味着每个BeanDefinitionParser将只包含解析单个定制元素的逻辑,我们将在下一步中看到这一点

9.2.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, we’ll 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:

  • 如果NamespaceHandler遇到了映射到特定bean定义解析器(在本例中是'dateformat')的类型的XML元素,那么将使用BeanDefinitionParser。换句话说,BeanDefinitionParser负责解析模式中定义的一个不同的顶级XML元素。在解析器中,我们可以访问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 { 

    protected Class getBeanClass(Element element) {
        return SimpleDateFormat.class; 
    }

    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));
        }
    }

}
We use the Spring-provided AbstractSingleBeanDefinitionParser to handle a lot of the basic grunt work of creating a single BeanDefinition.
We supply the AbstractSingleBeanDefinitionParser superclass with the type that our single BeanDefinition will represent.
  • 我们使用spring提供的AbstractSingleBeanDefinitionParser来处理创建单个BeanDefinition的大量繁琐的基本工作。

  • 我们为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 definition’s unique identifier.

  • 在这个简单的例子中,这就是我们所需要做的。单个BeanDefinition的创建是由AbstractSingleBeanDefinitionParser超类处理的,bean定义惟一标识符的提取和设置也是如此。

9.2.5. Registering the handler and the 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.

  • 编码完成了!剩下要做的就是使Spring XML解析基础设施知道我们的定制元素;我们通过在两个特殊用途的属性文件中注册我们的自定义namespaceHandler和自定义XSD文件来实现这一点。这些属性文件都放在应用程序的'META-INF'目录中,并且可以与二进制类一起分布在JAR文件中。Spring XML解析基础设施将通过使用这些特殊的属性文件自动获取您的新扩展,这些属性文件的格式将在下面详细介绍。
'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。包含XML模式uri到名称空间处理程序类的映射。因此,对于我们的示例,我们需要编写以下内容:
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属性格式中,':'字符是一个有效的分隔符,因此URI中的':'字符需要使用反斜杠进行转义。)

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,需要与自定义XSD模式中指定的'targetNamespace'属性的值精确匹配。
'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。Schema '包含XML模式位置(与使用模式作为'xsi:schemaLocation'属性一部分的XML文件中的模式声明一起引用)到类路径资源的映射。为了防止Spring使用需要Internet访问才能检索模式文件的默认EntityResolver,需要此文件。如果在这个属性文件中指定映射,Spring将搜索类路径上的模式(在本例中是'myns ')。sample中的xsd'。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文件与类路径中的NamespaceHandler和BeanDefinitionParser类一起部署。

9.2.6. Using a custom extension in your Spring XML configuration (在Spring XML配置中使用自定义扩展)

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 XML配置文件中使用前面步骤中开发的自定义元素的示例。
<?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>

9.2.7. Meatier examples(还有很多例子)

Find below some much meatier examples of custom XML extensions.

  • 下面是一些更丰富的自定义XML扩展示例。
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:

  • 这个例子说明了你可以如何编写各种工件来满足以下配置的目标:
<?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”属性公开setter方法;这使得使用setter注入为组件类配置bean定义变得困难(或者说不可能)。
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”属性公开setter属性。
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, we’ll start off by creating the XSD schema to define the structure of our custom tag.

  • 这一切都很好,并且工作得很好,但是向最终用户公开了许多Spring管道。我们要做的是编写一个自定义扩展,它隐藏了所有这些Spring管道。如果我们坚持前面描述的步骤,我们将从创建XSD模式开始,以定义定制标记的结构。
<?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>

We’ll 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。请记住,我们正在创建的是描述ComponentFactoryBean的BeanDefinition。
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.

  • 最后,需要向Spring XML基础设施注册各种工件。
# 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
Custom attributes on 'normal' elements(普通元素的自定义属性)

Writing your own custom parser and the associated artifacts isn’t 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 don’t 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.

  • 编写您自己的自定义解析器和相关工件并不困难,但有时这不是正确的做法。考虑这样一个场景,您需要向已经存在的bean定义添加元数据。在这种情况下,你当然不想去写你自己的整个自定义扩展;相反,您只需要向现有的bean定义元素添加额外的属性。

By way of another example, let’s 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定义,这个服务对象将(它不知道)访问一个聚集的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.

  • 我们在这里要做的是当'jcache:cache-name'属性被解析时创建另一个BeanDefinition;然后,这个BeanDefinition将为我们初始化命名的JCache。我们还将为“checkingAccountService”修改现有的BeanDefinition,以便它将依赖于这个新的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.

  • 最后,需要向Spring XML基础设施注册各种工件。
# 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

1. See Inversion of Control

  • 参见控制反转

2. See Dependency Injection

  • 看到依赖注入

3. But see also FileSystemResource caveats.

  • 但是也请参阅FileSystemResource警告。
posted @ 2020-09-29 10:53  六爻呈乾  阅读(196)  评论(0编辑  收藏  举报