对于最新的稳定版本,请使用 Spring Framework 6.2.4spring-doc.cadn.net.cn

容器扩展点

通常,应用程序开发人员不需要子类化ApplicationContextimplementation 类。相反,Spring IoC 容器可以通过插入来扩展 特殊集成接口的实现。接下来的几节将介绍这些 集成接口。spring-doc.cadn.net.cn

使用BeanPostProcessor

BeanPostProcessorinterface 定义您可以实现的回调方法 提供您自己的(或覆盖容器的默认)实例化逻辑、依赖项 resolution logic,依此类推。如果你想在 Spring 容器完成实例化、配置和初始化 bean 后,您可以 插入一个或多个自定义BeanPostProcessor实现。spring-doc.cadn.net.cn

您可以配置多个BeanPostProcessor实例,您可以控制 Order 其中这些BeanPostProcessor实例运行,方法是将order财产。 只有在BeanPostProcessor实现Ordered接口。如果您编写自己的BeanPostProcessor,您应该考虑实现 这Ordered界面也是如此。有关更多详细信息,请参阅BeanPostProcessorOrdered接口。另请参见程序化注册BeanPostProcessor实例.spring-doc.cadn.net.cn

BeanPostProcessor实例在 Bean(或对象)实例上运行。那是 Spring IoC 容器实例化一个 Bean 实例,然后BeanPostProcessor实例执行其工作。spring-doc.cadn.net.cn

BeanPostProcessor实例的范围是按容器划分的。这仅在您 使用容器层次结构。如果您定义了BeanPostProcessor在一个容器中, 它仅对该容器中的 bean 进行后处理。换句话说,是 不会由BeanPostProcessor定义于 另一个容器,即使两个容器都属于同一层次结构。spring-doc.cadn.net.cn

要更改实际的 Bean 定义(即定义 Bean 的 Blueprint),请执行以下作: 您需要改用BeanFactoryPostProcessor,如使用BeanFactoryPostProcessor.spring-doc.cadn.net.cn

org.springframework.beans.factory.config.BeanPostProcessor接口包括 恰好是两个回调方法。当此类注册为后处理器时,使用 容器中,对于容器创建的每个 bean 实例, 后处理器在容器之前从容器获取回调 初始化方法(如InitializingBean.afterPropertiesSet()或任何 宣布init方法)调用,并在任何 bean 初始化回调之后调用。 后处理器可以对 bean 实例执行任何作,包括忽略 callback 的 Quin 函数。bean 后处理器通常会检查回调接口, 或者它可能用代理包装 bean。一些 Spring AOP 基础设施类是 作为 Bean 后处理器实现,以提供代理包装逻辑。spring-doc.cadn.net.cn

ApplicationContext自动检测在 配置元数据,这些元数据实现BeanPostProcessor接口。这ApplicationContext将这些 bean 注册为后处理器,以便可以调用它们 稍后,在 bean 创建时。Bean 后处理器可以部署在容器中的 与任何其他Beans一样时尚。spring-doc.cadn.net.cn

请注意,在声明BeanPostProcessor通过使用@Beanfactory 方法在 configuration 类,则工厂方法的返回类型应为 implementation 类本身或至少org.springframework.beans.factory.config.BeanPostProcessor接口,清楚地指示该 Bean 的后处理器性质。否则,ApplicationContext在完全创建之前无法按类型自动检测它。 由于BeanPostProcessor需要提前实例化,以便应用于 初始化上下文中的其他 bean,这种早期类型检测至关重要。spring-doc.cadn.net.cn

以编程方式注册BeanPostProcessor实例
虽然BeanPostProcessor注册通过ApplicationContextauto-detection (如前所述),您可以注册它们 以编程方式针对ConfigurableBeanFactory通过使用addBeanPostProcessor方法。当您需要在 注册,甚至用于跨层次结构中的上下文复制 Bean 后处理器。 但请注意,BeanPostProcessor以编程方式添加的实例不遵循 这Ordered接口。在这里,是注册顺序决定了顺序 的执行。另请注意,BeanPostProcessor以编程方式注册的实例 始终在通过自动检测注册的 URL 之前处理,无论 显式排序。
BeanPostProcessor实例和 AOP 自动代理

实现BeanPostProcessor接口是特殊的,并经过处理 容器不同。都BeanPostProcessor实例和 bean 中,它们 直接引用在启动时实例化,作为特殊启动阶段的一部分 的ApplicationContext.接下来,所有BeanPostProcessor实例已注册 以排序的方式,并应用于容器中的所有其他 bean。因为 AOP auto-proxying 实现为BeanPostProcessor本身,也不会BeanPostProcessor实例和它们直接引用的 bean 都不符合自动代理的条件,并且 因此,不要将 aspects 编织到其中。spring-doc.cadn.net.cn

对于任何此类 bean,您应该会看到一条信息性日志消息:Bean someBean is not eligible for getting processed by all BeanPostProcessor interfaces (for example: not eligible for auto-proxying).spring-doc.cadn.net.cn

如果你有 bean 连接到你的BeanPostProcessor通过使用 Autowiring 或@Resource(可能会回退到自动装配),Spring 可能会访问意外的 bean 在搜索类型匹配的依赖项候选项时,因此,请将其 不符合自动代理或其他类型的 bean 后处理的条件。例如,如果你 具有注释有@Resource其中字段或 setter 名称没有 直接对应 bean 的声明名称,不使用 name 属性, Spring 访问其他 bean 以按类型匹配它们。spring-doc.cadn.net.cn

以下示例演示如何编写、注册和使用BeanPostProcessor实例 在ApplicationContext.spring-doc.cadn.net.cn

示例:Hello World、BeanPostProcessor-风格

第一个示例说明了基本用法。该示例显示了自定义BeanPostProcessor调用toString()方法作为 它由容器创建,并将生成的字符串打印到系统控制台。spring-doc.cadn.net.cn

以下清单显示了自定义BeanPostProcessorimplementation 类定义:spring-doc.cadn.net.cn

package scripting;

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;
	}
}
package scripting

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

The following beans element uses the InstantiationTracingBeanPostProcessor:spring-doc.cadn.net.cn

<?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>

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.)spring-doc.cadn.net.cn

The following Java application runs the preceding code and configuration:spring-doc.cadn.net.cn

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:spring-doc.cadn.net.cn

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

Example: The AutowiredAnnotationBeanPostProcessor

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.spring-doc.cadn.net.cn

Customizing Configuration Metadata with a BeanFactoryPostProcessor

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.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

As with BeanPostProcessors , you typically do not want to configure BeanFactoryPostProcessors 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

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.spring-doc.cadn.net.cn

Consider the following XML-based configuration metadata fragment, where a DataSource with placeholder values is defined:spring-doc.cadn.net.cn

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

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.spring-doc.cadn.net.cn

The actual values come from another file in the standard Java Properties format:spring-doc.cadn.net.cn

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

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-doc.cadn.net.cn

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:spring-doc.cadn.net.cn

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

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.spring-doc.cadn.net.cn

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 (${…​}).spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

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:spring-doc.cadn.net.cn

<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}"/>

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.spring-doc.cadn.net.cn

Example: The PropertyOverrideConfigurer

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.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

Properties file configuration lines take the following format:spring-doc.cadn.net.cn

beanName.property=value

The following listing shows an example of the format:spring-doc.cadn.net.cn

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

This example file can be used with a container definition that contains a bean called dataSource that has driverClassName and url properties.spring-doc.cadn.net.cn

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:spring-doc.cadn.net.cn

tom.fred.bob.sammy=123
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.

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:spring-doc.cadn.net.cn

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

Customizing Instantiation Logic with a FactoryBean

You can implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves factories.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

The FactoryBean<T> interface provides three methods:spring-doc.cadn.net.cn

  • 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.spring-doc.cadn.net.cn

  • boolean isSingleton(): Returns true if this FactoryBean returns singletons or false otherwise. The default implementation of this method returns true.spring-doc.cadn.net.cn

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

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.spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn