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.
BeanPostProcessorThe 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.
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 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 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.
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.
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.
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.
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
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
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.
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).
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.
The following examples show how to write, register, and use BeanPostProcessor instances in an
ApplicationContext.
BeanPostProcessor-styleThis 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.
The following listing shows the custom BeanPostProcessor implementation class definition:
The following beans element uses the InstantiationTracingBeanPostProcessor:
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.)
The following Java application runs the preceding code and configuration:
The output of the preceding application resembles the following: 前述应用程序的输出类似于以下:
Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961 org.springframework.scripting.groovy.GroovyMessenger@272961
AutowiredAnnotationBeanPostProcessor 示例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.
使用回调接口或注解与自定义的 BeanPostProcessor 实现相结合是扩展 Spring IoC 容器的一种常见方法。一个例子是 Spring 的
AutowiredAnnotationBeanPostProcessor ——这是一个随 Spring 发行版提供的 BeanPostProcessor 实现,它可以自动装配注解的字段、setter
方法和任意配置方法。
BeanFactoryPostProcessor
1.8.2. 使用 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.
接下来我们关注的扩展点是 org.springframework.beans.factory.config.BeanFactoryPostProcessor 。该接口的语义与
BeanPostProcessor 类似,但有一个主要区别: BeanFactoryPostProcessor 操作的是 bean 配置元数据。也就是说,Spring IoC
容器允许
BeanFactoryPostProcessor 读取配置元数据,并在容器实例化任何非 BeanFactoryPostProcessor 实例的 bean 之前,可能对其进行更改。
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.
你可以配置多个 BeanFactoryPostProcessor 实例,并且可以通过设置 order 属性来控制这些 BeanFactoryPostProcessor
实例的运行顺序。然而,只有当 BeanFactoryPostProcessor 实现了 Ordered 接口时,你才能设置此属性。如果你编写自己的
BeanFactoryPostProcessor ,也应考虑实现 Ordered 接口。有关更多详细信息,请参阅 BeanFactoryPostProcessor 和
Ordered
接口的 javadoc。
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.
如果你想更改实际的 bean 实例(即从配置元数据创建的对象),那么你需要使用 BeanPostProcessor (在通过
BeanPostProcessor
自定义 bean 中已描述)。虽然在技术上可以在 BeanFactoryPostProcessor 内处理 bean 实例(例如,通过使用
BeanFactory.getBean() ),这样做会导致 bean 实例化过早,违反标准容器生命周期。这可能会导致负面影响,例如绕过 bean 后处理。
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.
此外, BeanFactoryPostProcessor 实例是按容器范围定义的。这仅在你使用容器层次结构时相关。如果你在一个容器中定义了
BeanFactoryPostProcessor ,它仅应用于该容器中的 bean 定义。一个容器中的 bean 定义不会被另一个容器中的
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.
一个 Bean 工厂后处理器在声明在 ApplicationContext 内时自动运行,以便应用更改定义容器的配置元数据。Spring 包含多个预定义的
Bean 工厂后处理器,例如 PropertyOverrideConfigurer 和 PropertySourcesPlaceholderConfigurer 。你还可以使用自定义
BeanFactoryPostProcessor ——例如,用于注册自定义属性编辑器。
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.
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.
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.
Consider the following XML-based configuration metadata fragment, where a DataSource with placeholder values is
defined:
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.
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
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.
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:
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.
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:
你可以使用 PropertySourcesPlaceholderConfigurer 来替换类名,这在你需要在运行时选择特定实现类时有时很有用。以下示例展示了如何这样做:
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.
如果类在运行时无法解析为有效类,则在创建之前,即非懒加载 bean 的 ApplicationContext 阶段的
preInstantiateSingletons()
阶段,bean 的解析将失败。
PropertyOverrideConfigurer 示例:PropertyOverrideConfigurerThe 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.
PropertyOverrideConfigurer 是另一个 bean 工厂后处理器,类似于 PropertySourcesPlaceholderConfigurer
,但与后者不同,原始定义可以为
bean 属性设置默认值或根本不设置值。如果覆盖的 Properties 文件没有为某个 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.
请注意,Bean 定义不知道自己被覆盖了,因此从 XML 定义文件中无法立即看出正在使用覆盖配置器。如果有多个
PropertyOverrideConfigurer 实例为同一个 Bean 属性定义了不同的值,由于覆盖机制,最后一个值将生效。
Properties file configuration lines take the following format: 属性文件配置行采用以下格式:
The following listing shows an example of the format: 以下列表展示了格式示例:
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.
此示例文件可与包含名为 dataSource 的 bean 的容器定义一起使用,该 bean 具有 driverClassName 和 url 属性。
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 :
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. 指定的覆盖值始终是字面值。它们不会被转换为 Bean 引用。此约定也适用于当 XML Bean 定义中的原始值指定了 Bean 引用时。
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 2.5 中引入的 context 命名空间,可以配置使用专用配置元素来覆盖属性,如下例所示:
FactoryBean {#beans-factory-extension-factorybeanYou can implement the org.springframework.beans.factory.FactoryBean interface for objects that are themselves
factories.
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.
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.
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.
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.