此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
容器扩展点
通常,应用程序开发人员不需要子类化ApplicationContext
implementation 类。相反,Spring IoC 容器可以通过插入来扩展
特殊集成接口的实现。接下来的几节将介绍这些
集成接口。
使用BeanPostProcessor
这BeanPostProcessor
interface 定义您可以实现的回调方法
提供您自己的(或覆盖容器的默认)实例化逻辑、依赖项
resolution logic,依此类推。如果你想在
Spring 容器完成实例化、配置和初始化 bean 后,您可以
插入一个或多个自定义BeanPostProcessor
实现。
您可以配置多个BeanPostProcessor
实例,您可以控制 Order
其中这些BeanPostProcessor
实例运行,方法是将order
财产。
只有在BeanPostProcessor
实现Ordered
接口。如果您编写自己的BeanPostProcessor
,您应该考虑实现
这Ordered
界面也是如此。有关更多详细信息,请参阅BeanPostProcessor
和Ordered
接口。另请参见程序化注册BeanPostProcessor
实例.
要更改实际的 Bean 定义(即定义 Bean 的 Blueprint),请执行以下作:
您需要改用 |
这org.springframework.beans.factory.config.BeanPostProcessor
接口包括
恰好是两个回调方法。当此类注册为后处理器时,使用
容器中,对于容器创建的每个 bean 实例,
后处理器在容器之前从容器获取回调
初始化方法(如InitializingBean.afterPropertiesSet()
或任何
宣布init
方法)调用,并在任何 bean 初始化回调之后调用。
后处理器可以对 bean 实例执行任何作,包括忽略
callback 的 Quin 函数。bean 后处理器通常会检查回调接口,
或者它可能用代理包装 bean。一些 Spring AOP 基础设施类是
作为 Bean 后处理器实现,以提供代理包装逻辑。
一ApplicationContext
自动检测在
配置元数据,这些元数据实现BeanPostProcessor
接口。这ApplicationContext
将这些 bean 注册为后处理器,以便可以调用它们
稍后,在 bean 创建时。Bean 后处理器可以部署在容器中的
与任何其他Beans一样时尚。
请注意,在声明BeanPostProcessor
通过使用@Bean
factory 方法在
configuration 类,则工厂方法的返回类型应为 implementation
类本身或至少org.springframework.beans.factory.config.BeanPostProcessor
接口,清楚地指示该 Bean 的后处理器性质。否则,ApplicationContext
在完全创建之前无法按类型自动检测它。
由于BeanPostProcessor
需要提前实例化,以便应用于
初始化上下文中的其他 bean,这种早期类型检测至关重要。
以编程方式注册 虽然BeanPostProcessor 实例BeanPostProcessor 注册通过ApplicationContext auto-detection (如前所述),您可以注册它们
以编程方式针对ConfigurableBeanFactory 通过使用addBeanPostProcessor 方法。当您需要在
注册,甚至用于跨层次结构中的上下文复制 Bean 后处理器。
但请注意,BeanPostProcessor 以编程方式添加的实例不遵循
这Ordered 接口。在这里,是注册顺序决定了顺序
的执行。另请注意,BeanPostProcessor 以编程方式注册的实例
始终在通过自动检测注册的 URL 之前处理,无论
显式排序。 |
BeanPostProcessor 实例和 AOP 自动代理实现 对于任何此类 bean,您应该会看到一条信息性日志消息: 如果你有 bean 连接到你的 |
以下示例演示如何编写、注册和使用BeanPostProcessor
实例
在ApplicationContext
.
示例:Hello World、BeanPostProcessor
-风格
第一个示例说明了基本用法。该示例显示了自定义BeanPostProcessor
调用toString()
方法作为
它由容器创建,并将生成的字符串打印到系统控制台。
以下清单显示了自定义BeanPostProcessor
implementation 类定义:
-
Java
-
Kotlin
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
}
}
以下内容beans
元素使用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 动态语言支持在标题为“动态语言支持”的章节中进行了详细介绍。
以下 Java 应用程序运行上述代码和配置:
-
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)
}
上述应用程序的输出类似于以下内容:
Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961 org.springframework.scripting.groovy.GroovyMessenger@272961
使用BeanFactoryPostProcessor
我们要看的下一个扩展点是org.springframework.beans.factory.config.BeanFactoryPostProcessor
.的语义
此接口类似于BeanPostProcessor
,具有一个 Major
差异:BeanFactoryPostProcessor
对 Bean 配置元数据进行作。
也就是说,Spring IoC 容器允许BeanFactoryPostProcessor
阅读
配置元数据,并可能在容器实例化之前对其进行更改
除BeanFactoryPostProcessor
实例。
您可以配置多个BeanFactoryPostProcessor
实例,您可以在
这些BeanFactoryPostProcessor
实例运行,方法是将order
财产。
但是,只有在BeanFactoryPostProcessor
实现Ordered
接口。如果您编写自己的BeanFactoryPostProcessor
,您应该
考虑实施Ordered
界面也是如此。请参阅BeanFactoryPostProcessor
和Ordered
interfaces 了解更多详情。
如果要更改实际的 Bean 实例(即创建的对象
),那么您需要改用 也 |
当 bean 工厂后处理器在ApplicationContext
,以便将更改应用于
定义容器。Spring 包含许多预定义的 bean factory
后处理器,例如PropertyOverrideConfigurer
和PropertySourcesPlaceholderConfigurer
.您还可以使用自定义BeanFactoryPostProcessor
— 例如,注册自定义属性编辑器。
一ApplicationContext
自动检测部署到其中的任何 bean
实现BeanFactoryPostProcessor
接口。它将这些 bean 用作 bean factory
后处理器。您可以将这些后处理器 bean 部署为
你会喜欢任何其他豆子。
与 一样BeanPostProcessor s ,您通常不想配置BeanFactoryPostProcessor s 进行延迟初始化。如果没有其他 bean 引用Bean(Factory)PostProcessor ,该后处理器根本不会被实例化。
因此,将其标记为延迟初始化将被忽略,并且Bean(Factory)PostProcessor 将预先实例化,即使您将default-lazy-init 属性设置为true 在您的<beans /> 元素。 |
示例:类名替换PropertySourcesPlaceholderConfigurer
您可以使用PropertySourcesPlaceholderConfigurer
外部化属性值
使用标准 Java 从单独文件中的 bean 定义Properties
格式。
这样做使部署应用程序的人员能够自定义特定于环境的
属性(例如数据库 URL 和密码),而不会产生
修改容器的一个或多个主 XML 定义文件。
请考虑以下基于 XML 的配置元数据片段,其中DataSource
with placeholder values 定义:
<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
文件。在运行时,
一个PropertySourcesPlaceholderConfigurer
应用于元数据,该元数据将替换某些
属性。要替换的值指定为
形式${property-name}
,它遵循 Ant 和 log4j 以及 JSP EL 样式。
实际值来自标准 Java 中的另一个文件Properties
格式:
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
因此,${jdbc.username}
string 在运行时替换为值 'sa' 和
这同样适用于与 Properties 文件中的键匹配的其他占位符值。
这PropertySourcesPlaceholderConfigurer
检查大多数属性中的占位符,以及
bean 定义的属性。此外,您还可以自定义占位符前缀和后缀。
使用context
namespace 中引入的,你可以配置属性占位符
替换为专用的配置元素。您可以将一个或多个位置作为
逗号分隔的列表location
属性,如下例所示:
<context:property-placeholder location="classpath:com/something/jdbc.properties"/>
这PropertySourcesPlaceholderConfigurer
不仅在Properties
文件。默认情况下,如果在指定的属性文件中找不到属性,则
它检查 SpringEnvironment
properties 和常规 JavaSystem
性能。
对于具有
它需要。可以配置多个属性占位符,只要它们具有不同的
placeholder 语法 ( 如果需要模块化用于替换的属性源,则应
不创建多个属性占位符。相反,您应该创建自己的 |
您可以使用
如果该类在运行时无法解析为有效类,则 Bean 的解析
在即将创建时失败,即在 |
示例:PropertyOverrideConfigurer
这PropertyOverrideConfigurer
,另一个 Bean Factory 后处理器,类似于PropertySourcesPlaceholderConfigurer
,但与后者不同的是,原始定义
可以为 Bean 属性设置默认值或根本没有值。如果 overoverrideProperties
file 没有某个 Bean 属性的条目,则默认的
上下文定义。
请注意,bean 定义不知道被覆盖,因此它不是
从 XML 定义文件中可以立即明显看出 override configurer 正在
使用。如果有多个PropertyOverrideConfigurer
定义不同
值,由于覆盖机制,最后一个 Bean 属性优先。
Properties 文件配置行采用以下格式:
beanName.property=value
下面的清单显示了格式的示例:
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
此示例文件可以与容器定义一起使用,该容器定义包含名为dataSource
该driverClassName
和url
性能。
还支持复合属性名称,只要路径的每个组件
除了被覆盖的最终属性已经是非 null 的(大概是初始化的
由构造函数)。在以下示例中,sammy
属性的bob
属性的fred
属性的tom
bean 设置为 Scalar 值123
:
tom.fred.bob.sammy=123
指定的覆盖值始终是文本值。它们不会被翻译成 bean 引用。当 XML Bean 中的原始值 definition 指定 bean 引用。 |
使用context
namespace 中引入的,则可以配置
属性替换为专用的 configuration 元素,如下例所示:
<context:property-override location="classpath:override.properties"/>
使用FactoryBean
您可以实现org.springframework.beans.factory.FactoryBean
对象的接口
本身就是工厂。
这FactoryBean
interface 是 Spring IoC 容器的
实例化逻辑。如果你有复杂的初始化代码,最好用
与 Java 相比,您可以创建自己的 XMLFactoryBean
,在该类中编写复杂的初始化,然后将
习惯FactoryBean
放入容器中。
这FactoryBean<T>
interface 提供了三种方法:
-
T getObject()
:返回此工厂创建的对象的实例。这 实例可以共享,具体取决于此工厂是否返回单例 或原型。 -
boolean isSingleton()
:返回true
如果此FactoryBean
返回单例或false
否则。此方法的默认实现返回true
. -
Class<?> getObjectType()
:返回getObject()
方法 或null
如果事先不知道类型。
这FactoryBean
concept 和 interface 在 Spring 中的许多地方使用
框架。超过 50 种FactoryBean
与 Spring 的接口
本身。
当您需要向容器询问实际FactoryBean
实例本身而不是
它生成的 bean 会作为 bean 的id
当
调用&
getBean()
方法ApplicationContext
.因此,对于给定的FactoryBean
替换为id
之myBean
调用getBean("myBean")
在容器上返回
的产品FactoryBean
,而调用getBean("&myBean")
返回FactoryBean
实例本身。