Container Extension Points

通常,应用程序开发人员不需要对 ApplicationContext 实现类进行子类化。相反,Spring IoC 容器可以通过插入特殊集成接口的实现来进行扩展。接下来的几个部分描述了这些集成接口。

Typically, an application developer does not need to subclass ApplicationContext implementation classes. Instead, the Spring IoC container can be extended by plugging in implementations of special integration interfaces. The next few sections describe these integration interfaces.

Customizing Beans by Using a BeanPostProcessor

BeanPostProcessor 接口定义了你能够实现的回调方法,以便提供你自己的(或覆盖容器的默认)实例化逻辑、依赖解析逻辑等等。如果你想要在 Spring 容器完成一个 bean 的实例化、配置和初始化之后实现一些自定义逻辑,你可以插入一个或多个自定义的 BeanPostProcessor 实现。

The BeanPostProcessor interface defines callback methods that you can implement to provide your own (or override the container’s default) instantiation logic, dependency resolution logic, and so forth. If you want to implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more custom BeanPostProcessor implementations.

你可以配置多个 BeanPostProcessor 实例,并且你可以通过设置 order 属性来控制这些 BeanPostProcessor 实例运行的顺序。如果 BeanPostProcessor 实现了 Ordered 接口,你只能设置此属性。如果你编写自己的 BeanPostProcessor,你应该考虑也实现 Ordered 接口。有关更多详细信息,请参阅 BeanPostProcessorOrdered 接口的 javadoc。另请参阅 programmatic registration of BeanPostProcessor instances 中的注释。

You can configure multiple BeanPostProcessor instances, and you can control the order in which these BeanPostProcessor instances run by setting the order property. You can set this property only if the BeanPostProcessor implements the Ordered interface. If you write your own BeanPostProcessor, you should consider implementing the Ordered interface, too. For further details, see the javadoc of the BeanPostProcessor and Ordered interfaces. See also the note on programmatic registration of BeanPostProcessor instances.

BeanPostProcessor 实例对 bean(或对象)实例执行操作。也就是说,Spring IoC 容器实例化一个 bean 实例,然后 BeanPostProcessor 实例执行它们的工作。

BeanPostProcessor instances operate on bean (or object) instances. That is, the Spring IoC container instantiates a bean instance and then BeanPostProcessor instances do their work.

BeanPostProcessor 实例是针对每个容器进行设置范围的。这仅在使用容器层次结构时才相关。如果你在一个容器中定义了一个 BeanPostProcessor,它只会对该容器中的 bean 执行后处理。换句话说,在一个容器中定义的 bean 不会由另一个容器中定义的 BeanPostProcessor 执行后处理,即使这两个容器是同一层次结构的一部分。

BeanPostProcessor instances are scoped per-container. This is relevant only if you use container hierarchies. If you define a BeanPostProcessor in one container, it post-processes only the beans in that container. In other words, beans that are defined in one container are not post-processed by a BeanPostProcessor defined in another container, even if both containers are part of the same hierarchy.

要更改实际 bean 定义(即定义 bean 的蓝图),您需要使用 BeanFactoryPostProcessor,如 xref:core/beans/factory-extension.adoc#beans-factory-extension-factory-postprocessors[Customizing Configuration Metadata with a BeanFactoryPostProcessor 中所述。

To change the actual bean definition (that is, the blueprint that defines the bean), you instead need to use a BeanFactoryPostProcessor, as described in Customizing Configuration Metadata with a BeanFactoryPostProcessor.

org.springframework.beans.factory.config.BeanPostProcessor 接口恰好由两个回调方法组成。当此类作为后处理器向容器注册时,对于容器创建的每个 bean 实例,该后处理器都会在调用容器初始化方法(例如 InitializingBean.afterPropertiesSet() 或任何已声明的 init 方法)之前和在任何 bean 初始化回调之后从容器中获得一个回调。该后处理器可以对 bean 实例采取任何操作,包括完全忽略该回调。一个 bean 后处理器通常会检查回调接口,或者它可能会使用代理包装一个 bean。某些 Spring AOP 基础架构类被实现为 bean 后处理器,以便提供代理包装逻辑。

The org.springframework.beans.factory.config.BeanPostProcessor interface consists of exactly two callback methods. When such a class is registered as a post-processor with the container, for each bean instance that is created by the container, the post-processor gets a callback from the container both before container initialization methods (such as InitializingBean.afterPropertiesSet() or any declared init method) are called, and after any bean initialization callbacks. The post-processor can take any action with the bean instance, including ignoring the callback completely. A bean post-processor typically checks for callback interfaces, or it may wrap a bean with a proxy. Some Spring AOP infrastructure classes are implemented as bean post-processors in order to provide proxy-wrapping logic.

ApplicationContext 会自动检测在配置元数据中定义的所有实现 BeanPostProcessor 接口的 bean。ApplicationContext 将这些 bean 注册为后处理器,以便稍后在创建 bean 时对它们进行调用。可以像部署任何其他 bean 一样在容器中部署 bean 后处理器。

An ApplicationContext automatically detects any beans that are defined in the configuration metadata that implement the BeanPostProcessor interface. The ApplicationContext registers these beans as post-processors so that they can be called later, upon bean creation. Bean post-processors can be deployed in the container in the same fashion as any other beans.

请注意,在配置类中使用 @Bean 工厂方法声明 BeanPostProcessor 时,工厂方法的返回类型应为实现类本身或至少为 org.springframework.beans.factory.config.BeanPostProcessor 接口,明确指示该 bean 的后处理器性质。否则,ApplicationContext 在完全创建该 bean 之前无法通过类型自动检测到它。由于必须尽早实例化 BeanPostProcessor 以便对其应用上下文中的其他 bean 的初始化,因此这种早期类型检测至关重要。

Note that, when declaring a BeanPostProcessor by using an @Bean factory method on a configuration class, the return type of the factory method should be the implementation class itself or at least the org.springframework.beans.factory.config.BeanPostProcessor interface, clearly indicating the post-processor nature of that bean. Otherwise, the ApplicationContext cannot autodetect it by type before fully creating it. Since a BeanPostProcessor needs to be instantiated early in order to apply to the initialization of other beans in the context, this early type detection is critical.

Programmatically registering BeanPostProcessor instances

尽管 @{13} 注册的推荐方法是通过 @{14} 自动检测(如前文所述),但你可以使用 @{16} 方法对照一个 @{15} 以编程方式注册它们。这在需要在注册前评估条件逻辑或即使在层次结构中的上下文间复制 bean 后置处理器时很有用。但是请注意,以编程方式添加的 @{17} 实例并不遵守 @{18} 接口。这里,执行顺序由注册顺序决定。另请注意,以编程方式注册的 @{19} 实例总是比通过自动检测注册的实例先处理,而不管显式排序如何。

Programmatically registering BeanPostProcessor instances

While the recommended approach for BeanPostProcessor registration is through ApplicationContext auto-detection (as described earlier), you can register them programmatically against a ConfigurableBeanFactory by using the addBeanPostProcessor method. This can be useful when you need to evaluate conditional logic before registration or even for copying bean post processors across contexts in a hierarchy. Note, however, that BeanPostProcessor instances added programmatically do not respect the Ordered interface. Here, it is the order of registration that dictates the order of execution. Note also that BeanPostProcessor instances registered programmatically are always processed before those registered through auto-detection, regardless of any explicit ordering.

BeanPostProcessor instances and AOP auto-proxying

实现 BeanPostProcessor 接口的类是特殊的,并以不同方式由容器进行处理。所有 BeanPostProcessor 实例和它们直接引用的 bean 都在启动时进行实例化,作为 ApplicationContext 特殊启动阶段的一部分。接下来,所有 BeanPostProcessor 实例都会以已排序的方式进行注册,并应用于容器中的所有进一步的 bean。由于 AOP 自动代理本身是作为 BeanPostProcessor 实现的,因此 BeanPostProcessor 实例及其直接引用的 bean 都没有资格进行自动代理处理,因此没有将方面编织到它们中。

Classes that implement the BeanPostProcessor interface are special and are treated differently by the container. All BeanPostProcessor instances and beans that they directly reference are instantiated on startup, as part of the special startup phase of the ApplicationContext. Next, all BeanPostProcessor instances are registered in a sorted fashion and applied to all further beans in the container. Because AOP auto-proxying is implemented as a BeanPostProcessor itself, neither BeanPostProcessor instances nor the beans they directly reference are eligible for auto-proxying and, thus, do not have aspects woven into them.

对于任何此类 bean,你都应看到一条信息日志消息:Bean someBean 没有资格由所有 BeanPostProcessor 接口进行处理(例如:不符合自动代理条件)

For any such bean, you should see an informational log message: Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying).

如果你使用自动装配或 @Resource(它可能会回退到自动装配)将 bean 连接到你的 BeanPostProcessor 中,Spring 可能会在搜索匹配类型的依赖项候选时访问意外的 bean,因此使它们没有资格进行自动代理处理或其他类型的 bean 后处理。例如,如果你有一个使用 @Resource 进行注释的依赖项,其中字段或 setter 名称与 bean 的声明名称直接不对应,并且未使用名称属性,则 Spring 会通过类型访问其他 bean 以对其进行匹配。

If you have beans wired into your BeanPostProcessor by using autowiring or @Resource (which may fall back to autowiring), Spring might access unexpected beans when searching for type-matching dependency candidates and, therefore, make them ineligible for auto-proxying or other kinds of bean post-processing. For example, if you have a dependency annotated with @Resource where the field or setter name does not directly correspond to the declared name of a bean and no name attribute is used, Spring accesses other beans for matching them by type.

下面的示例展示了如何在 ApplicationContext 中编写、注册和使用 BeanPostProcessor 实例。

The following examples show how to write, register, and use BeanPostProcessor instances in an ApplicationContext.

Example: Hello World, BeanPostProcessor-style

第一个示例说明了基本用法。该示例显示了一个自定义的 BeanPostProcessor 实现,它调用容器创建的每个 bean 的 toString() 方法,并将结果字符串打印到系统控制台上。

This first example illustrates basic usage. The example shows a custom BeanPostProcessor implementation that invokes the toString() method of each bean as it is created by the container and prints the resulting string to the system console.

下面的列表展示了自定义 BeanPostProcessor 实现类定义:

The following listing shows the custom BeanPostProcessor implementation class definition:

  • Java

  • Kotlin

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

public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {

	// simply return the instantiated bean as-is
	public Object postProcessBeforeInitialization(Object bean, String beanName) {
		return bean; // we could potentially return any object reference here...
	}

	public Object postProcessAfterInitialization(Object bean, String beanName) {
		System.out.println("Bean '" + beanName + "' created : " + bean.toString());
		return bean;
	}
}
import org.springframework.beans.factory.config.BeanPostProcessor

class InstantiationTracingBeanPostProcessor : BeanPostProcessor {

	// simply return the instantiated bean as-is
	override fun postProcessBeforeInitialization(bean: Any, beanName: String): Any? {
		return bean // we could potentially return any object reference here...
	}

	override fun postProcessAfterInitialization(bean: Any, beanName: String): Any? {
		println("Bean '$beanName' created : $bean")
		return bean
	}
}

以下 beans 元素使用了 InstantiationTracingBeanPostProcessor

The following beans element uses the InstantiationTracingBeanPostProcessor:

<?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:lang="http://www.springframework.org/schema/lang"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/lang
		https://www.springframework.org/schema/lang/spring-lang.xsd">

	<lang:groovy id="messenger"
			script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
		<lang:property name="message" value="Fiona Apple Is Just So Dreamy."/>
	</lang:groovy>

	<!--
	when the above bean (messenger) is instantiated, this custom
	BeanPostProcessor implementation will output the fact to the system console
	-->
	<bean class="scripting.InstantiationTracingBeanPostProcessor"/>

</beans>

请注意 `InstantiationTracingBeanPostProcessor`是如何被定义的。它甚至没有一个名称,并且,因为它是一个 Bean,它可以像依赖注入任何其他 Bean 一样被注入依赖项。(前面的配置还定义了一个由 Groovy 脚本支持的 Bean。Spring 动态语言支持在题为 Dynamic Language Support的章节中进行了详细说明。)

Notice how the InstantiationTracingBeanPostProcessor is merely defined. It does not even have a name, and, because it is a bean, it can be dependency-injected as you would any other bean. (The preceding configuration also defines a bean that is backed by a Groovy script. The Spring dynamic language support is detailed in the chapter entitled Dynamic Language Support.)

以下 Java 应用程序运行了前面的代码和配置:

The following Java application runs the preceding code and configuration:

  • Java

  • Kotlin

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;

public final class Boot {

	public static void main(final String[] args) throws Exception {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml");
		Messenger messenger = ctx.getBean("messenger", Messenger.class);
		System.out.println(messenger);
	}

}
   import org.springframework.beans.factory.getBean

fun main() {
	val ctx = ClassPathXmlApplicationContext("scripting/beans.xml")
	val messenger = ctx.getBean<Messenger>("messenger")
	println(messenger)
}

前一个应用程序的输出类似于以下内容:

The output of the preceding application resembles the following:

Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961 org.springframework.scripting.groovy.GroovyMessenger@272961

Example: The AutowiredAnnotationBeanPostProcessor

连同自定义 BeanPostProcessor 实现一起使用回调接口或注解是扩展 Spring IoC 容器的常见方法。一个示例是 Spring 的 AutowiredAnnotationBeanPostProcessor——一个随 Spring 分发一起提供的 BeanPostProcessor 实现,可自动装配带注解的字段、setter 方法和任意配置方法。

Using callback interfaces or annotations in conjunction with a custom BeanPostProcessor implementation is a common means of extending the Spring IoC container. An example is Spring’s AutowiredAnnotationBeanPostProcessor — a BeanPostProcessor implementation that ships with the Spring distribution and autowires annotated fields, setter methods, and arbitrary config methods.

Customizing Configuration Metadata with a BeanFactoryPostProcessor

我们将研究的下一个扩展点是 org.springframework.beans.factory.config.BeanFactoryPostProcessor。此接口的语义与 BeanPostProcessor 的语义类似,但有一个主要区别:BeanFactoryPostProcessor 对 Bean 配置元数据进行操作。也就是说,Spring IoC 容器允许 BeanFactoryPostProcessor 读取配置元数据并在容器实例化除 BeanFactoryPostProcessor 实例之外的任何 Bean 之前对其进行更改。

The next extension point that we look at is the org.springframework.beans.factory.config.BeanFactoryPostProcessor. The semantics of this interface are similar to those of the BeanPostProcessor, with one major difference: BeanFactoryPostProcessor operates on the bean configuration metadata. That is, the Spring IoC container lets a BeanFactoryPostProcessor read the configuration metadata and potentially change it before the container instantiates any beans other than BeanFactoryPostProcessor instances.

您可以配置多个 BeanFactoryPostProcessor`实例,并可通过设置 `order`属性来控制这些 `BeanFactoryPostProcessor`实例的运行顺序。但是,仅当 `BeanFactoryPostProcessor`实现 `Ordered`接口时,您才能设置此属性。如果您编写了自己的 `BeanFactoryPostProcessor,您还应考虑实现 Ordered`接口。有关详细信息,请参阅 `BeanFactoryPostProcessorOrdered 接口的 javadoc。

You can configure multiple BeanFactoryPostProcessor instances, and you can control the order in which these BeanFactoryPostProcessor instances run by setting the order property. However, you can only set this property if the BeanFactoryPostProcessor implements the Ordered interface. If you write your own BeanFactoryPostProcessor, you should consider implementing the Ordered interface, too. See the javadoc of the BeanFactoryPostProcessor and Ordered interfaces for more details.

如果您想更改实际 bean 实例(即从配置元数据创建的对象),那么您需要使用 BeanPostProcessor(在 xref:core/beans/factory-extension.adoc#beans-factory-extension-bpp[Customizing Beans by Using a BeanPostProcessor 中前面已经介绍)。虽然可以在 BeanFactoryPostProcessor 中使用 bean 实例(例如使用 BeanFactory.getBean()),但这会导致过早的 bean 实例化,从而违反标准容器生命周期。这可能会引起负面副作用,例如绕过 bean 后期处理。

If you want to change the actual bean instances (that is, the objects that are created from the configuration metadata), then you instead need to use a BeanPostProcessor (described earlier in Customizing Beans by Using a BeanPostProcessor). While it is technically possible to work with bean instances within a BeanFactoryPostProcessor (for example, by using BeanFactory.getBean()), doing so causes premature bean instantiation, violating the standard container lifecycle. This may cause negative side effects, such as bypassing bean post processing.

此外,BeanFactoryPostProcessor 实例的范围为每个容器。仅当您使用容器层次结构时,这才是相关的。如果您在某个容器中定义了 BeanFactoryPostProcessor,它仅适用于该容器中的 Bean 定义。一个容器中的 Bean 定义不会由另一个容器中的 BeanFactoryPostProcessor 实例后处理,即使这两个容器是同一层次结构的一部分。

Also, BeanFactoryPostProcessor instances are scoped per-container. This is only relevant if you use container hierarchies. If you define a BeanFactoryPostProcessor in one container, it is applied only to the bean definitions in that container. Bean definitions in one container are not post-processed by BeanFactoryPostProcessor instances in another container, even if both containers are part of the same hierarchy.

为了对定义容器的配置元数据应用更改,会在 ApplicationContext 内声明 Bean 工厂后处理器时自动运行它。Spring 包含许多预定义的 Bean 工厂后处理器,如 PropertyOverrideConfigurerPropertySourcesPlaceholderConfigurer。您还可以使用自定义 BeanFactoryPostProcessor——例如,注册自定义属性编辑器。

A bean factory post-processor is automatically run when it is declared inside an ApplicationContext, in order to apply changes to the configuration metadata that define the container. Spring includes a number of predefined bean factory post-processors, such as PropertyOverrideConfigurer and PropertySourcesPlaceholderConfigurer. You can also use a custom BeanFactoryPostProcessor — for example, to register custom property editors.

ApplicationContext 会自动检测部署到其中并实现了 BeanFactoryPostProcessor 接口的任何 Bean。它在适当的时间以 Bean 工厂后处理器的形式使用这些 Bean。您可以按您使用任何其他 Bean 的方式部署这些后处理器 Bean。

An ApplicationContext automatically detects any beans that are deployed into it that implement the BeanFactoryPostProcessor interface. It uses these beans as bean factory post-processors, at the appropriate time. You can deploy these post-processor beans as you would any other bean.

与 @{38} 一样,该后处理器根本不会实例化。因此,将其标记为惰性初始化将被忽略,即使你在 @{42} 元素的声明中将 @{40} 属性设置为 @{41},@{39} 也将立即实例化。

As with BeanPostProcessor`s , you typically do not want to configure `BeanFactoryPostProcessor`s for lazy initialization. If no other bean references a `Bean(Factory)PostProcessor, that post-processor will not get instantiated at all. Thus, marking it for lazy initialization will be ignored, and the Bean(Factory)PostProcessor will be instantiated eagerly even if you set the default-lazy-init attribute to true on the declaration of your <beans /> element.

Example: The Class Name Substitution PropertySourcesPlaceholderConfigurer

您可以使用 PropertySourcesPlaceholderConfigurer 将 Bean 定义中的属性值从一个单独的文件中提取出来,方法是使用标准的 Java Properties 格式。这使部署应用程序的人能够自定义特定于环境的属性(如数据库 URL 和密码),而不用修改主 XML 定义文件或容器文件,从而省去了复杂性或降低了风险。

You can use the PropertySourcesPlaceholderConfigurer to externalize property values from a bean definition in a separate file by using the standard Java Properties format. Doing so enables the person deploying an application to customize environment-specific properties, such as database URLs and passwords, without the complexity or risk of modifying the main XML definition file or files for the container.

考虑以下基于 XML 的配置元数据片段,其中定义了一个带占位符值的 DataSource

Consider the following XML-based configuration metadata fragment, where a DataSource with placeholder values is defined:

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
	<property name="locations" value="classpath:com/something/jdbc.properties"/>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<property name="driverClassName" value="${jdbc.driverClassName}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</bean>

该示例显示了从一个外部 Properties 文件配置的属性。在运行时,会对替换 DataSource 的某些属性的元数据应用 PropertySourcesPlaceholderConfigurer。要替换的值指定为 ${property-name} 形式的占位符,它遵循 Ant、log4j 和 JSP EL 样式。

The example shows properties configured from an external Properties file. At runtime, a PropertySourcesPlaceholderConfigurer is applied to the metadata that replaces some properties of the DataSource. The values to replace are specified as placeholders of the form ${property-name}, which follows the Ant and log4j and JSP EL style.

实际的值来自另一个文件,格式为标准的 Java Properties

The actual values come from another file in the standard Java Properties format:

jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root

因此,字符串 ${jdbc.username} 在运行时替换为值“sa”,并且相同适用于与属性文件中键匹配的其他占位符值。PropertySourcesPlaceholderConfigurer 会检查 Bean 定义的大多数属性和特征中的占位符。此外,您可以自定义占位符的前缀和后缀。

Therefore, the ${jdbc.username} string is replaced at runtime with the value, 'sa', and the same applies for other placeholder values that match keys in the properties file. The PropertySourcesPlaceholderConfigurer checks for placeholders in most properties and attributes of a bean definition. Furthermore, you can customize the placeholder prefix and suffix.

借助 Spring 2.5 中引入的 context 命名空间,您可以使用专门的配置元素配置属性占位符。您可以在 location 属性中以逗号分隔列表的形式提供一个或多个位置,如下面的示例所示:

With the context namespace introduced in Spring 2.5, you can configure property placeholders with a dedicated configuration element. You can provide one or more locations as a comma-separated list in the location attribute, as the following example shows:

<context:property-placeholder location="classpath:com/something/jdbc.properties"/>

PropertySourcesPlaceholderConfigurer 不仅会在您指定的 Properties 文件中查找属性。默认情况下,如果它在指定的属性文件中找不到属性,它会针对 Spring Environment 属性和常规 Java System 属性进行检查。

The PropertySourcesPlaceholderConfigurer not only looks for properties in the Properties file you specify. By default, if it cannot find a property in the specified properties files, it checks against Spring Environment properties and regular Java System properties.

对于给定的应用程序,只应使用它所需的属性定义一个这样的元素。只要占位符语法不同(${…​}),则可以配置多个属性占位符。

Only one such element should be defined for a given application with the properties that it needs. Several property placeholders can be configured as long as they have distinct placeholder syntax (${…​}).

如果您需要模块化用于替换的属性源,您不应该创建多个属性占位符。相反,您应该创建自己的 PropertySourcesPlaceholderConfigurer Bean,用于收集要使用的属性。

If you need to modularize the source of properties used for the replacement, you should not create multiple properties placeholders. Rather, you should create your own PropertySourcesPlaceholderConfigurer bean that gathers the properties to use.

您可以使用 PropertySourcesPlaceholderConfigurer 替换类名,在运行时必须选择某个特定的实现类时,这有时很有用。以下示例说明了如何执行此操作:

You can use the PropertySourcesPlaceholderConfigurer to substitute class names, which is sometimes useful when you have to pick a particular implementation class at runtime. The following example shows how to do so:

<bean class="org.springframework.beans.factory.config.PropertySourcesPlaceholderConfigurer">
	<property name="locations">
		<value>classpath:com/something/strategy.properties</value>
	</property>
	<property name="properties">
		<value>custom.strategy.class=com.something.DefaultStrategy</value>
	</property>
</bean>

<bean id="serviceStrategy" class="${custom.strategy.class}"/>

如果类在运行时不能解析为有效的类,则当 Bean 即将创建时(对于非延迟初始化 Bean,是在 ApplicationContextpreInstantiateSingletons() 阶段),Bean 的解析将失败。

If the class cannot be resolved at runtime to a valid class, resolution of the bean fails when it is about to be created, which is during the preInstantiateSingletons() phase of an ApplicationContext for a non-lazy-init bean.

Example: The PropertyOverrideConfigurer

PropertyOverrideConfigurer 是另一个 Bean 工厂后处理器,类似于 PropertySourcesPlaceholderConfigurer,但是与后者不同,对于 Bean 属性,原始的定义可以有默认值,也可以没有任何值。如果重写的 Properties 文件没有特定 Bean 属性的条目,则使用默认的上下文定义。

The PropertyOverrideConfigurer, another bean factory post-processor, resembles the PropertySourcesPlaceholderConfigurer, but unlike the latter, the original definitions can have default values or no values at all for bean properties. If an overriding Properties file does not have an entry for a certain bean property, the default context definition is used.

注意,bean 定义并不知道被覆盖,因此从 XML 定义文件中并不立即明显,正在使用覆盖配置器。如果有多个 PropertyOverrideConfigurer 实例为同一 bean 属性定义不同的值,则由于覆盖机制,最后一个值获胜。

Note that the bean definition is not aware of being overridden, so it is not immediately obvious from the XML definition file that the override configurer is being used. In case of multiple PropertyOverrideConfigurer instances that define different values for the same bean property, the last one wins, due to the overriding mechanism.

属性文件配置行采用以下格式:

Properties file configuration lines take the following format:

beanName.property=value

以下列表显示了一个示例格式:

The following listing shows an example of the format:

dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb

此示例文件可与包含一个名为 dataSource 的 bean 的容器定义一起使用,该 bean 具有 driverClassNameurl 属性。

This example file can be used with a container definition that contains a bean called dataSource that has driverClassName and url properties.

只要路径的每个组成部分(除了要覆盖的最终属性)已经为非空(大概由构造函数初始化),复合属性名称也受支持。在以下示例中,tom bean 的 fred 属性的 bob 属性的 sammy 属性被设置为标量值 123

Compound property names are also supported, as long as every component of the path except the final property being overridden is already non-null (presumably initialized by the constructors). In the following example, the sammy property of the bob property of the fred property of the tom bean is set to the scalar value 123:

tom.fred.bob.sammy=123

指定的覆盖值始终是被文字值。它们不会翻译成 bean 引用。当 XML bean 定义中的原始值指定一个 bean 引用时,此约定也適用。

Specified override values are always literal values. They are not translated into bean references. This convention also applies when the original value in the XML bean definition specifies a bean reference.

Spring 2.5 中引入的 context 命名空间允许使用专用配置元素配置属性覆盖,如下例所示:

With the context namespace introduced in Spring 2.5, it is possible to configure property overriding with a dedicated configuration element, as the following example shows:

<context:property-override location="classpath:override.properties"/>

Customizing Instantiation Logic with a FactoryBean

您可以为本身是工厂的对象实现 org.springframework.beans.factory.FactoryBean 接口。

You can implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.

FactoryBean 接口是插入 Spring IoC 容器实例化逻辑的一个切入点。如果您有复杂的初始化代码,用 Java 编写会好于(潜在的)大量的 XML,则可以创建自己的 FactoryBean,在该类中编写复杂的初始化代码,然后将您自定义的 FactoryBean 插入容器。

The FactoryBean interface is a point of pluggability into the Spring IoC container’s instantiation logic. If you have complex initialization code that is better expressed in Java as opposed to a (potentially) verbose amount of XML, you can create your own FactoryBean, write the complex initialization inside that class, and then plug your custom FactoryBean into the container.

FactoryBean<T> 接口提供了三种方法:

The FactoryBean<T> interface provides three methods:

  • T getObject(): Returns an instance of the object this factory creates. The instance can possibly be shared, depending on whether this factory returns singletons or prototypes.

  • boolean isSingleton(): Returns true if this FactoryBean returns singletons or false otherwise. The default implementation of this method returns true.

  • Class<?> getObjectType(): Returns the object type returned by the getObject() method or null if the type is not known in advance.

FactoryBean 概念和接口在 Spring Framework 中的多个位置使用。FactoryBean 接口有 50 多个实现与 Spring 本身一起提供。

The FactoryBean concept and interface are used in a number of places within the Spring Framework. More than 50 implementations of the FactoryBean interface ship with Spring itself.

当您需要向容器请求实际的 FactoryBean 实例而不是它生成 bean 时,在调用 ApplicationContextgetBean() 方法时,使用 & 符号为 bean 的 id 加前缀。因此,对于具有 idmyBean 的给定的 FactoryBean,对容器调用 getBean("myBean") 会返回 FactoryBean 的产品,而调用 getBean("&myBean") 会返回 FactoryBean 实例本身。

When you need to ask a container for an actual FactoryBean instance itself instead of the bean it produces, prefix the bean’s id with the ampersand symbol (&) when calling the getBean() method of the ApplicationContext. So, for a given FactoryBean with an id of myBean, invoking getBean("myBean") on the container returns the product of the FactoryBean, whereas invoking getBean("&myBean") returns the FactoryBean instance itself.