此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
容器扩展点
通常,应用程序开发人员不需要将ApplicationContext
实现类。相反,可以通过插入
特殊集成接口的实现。接下来的几节将介绍这些
集成接口。
使用BeanPostProcessor
这BeanPostProcessor
接口定义了可以实现的回调方法
提供您自己的(或覆盖容器的默认)实例化逻辑、依赖项
解析逻辑,依此类推。如果你想在
Spring 容器完成实例化、配置和初始化 bean,您可以
插入一个或多个自定义BeanPostProcessor
实现。
您可以配置多个BeanPostProcessor
实例,您可以控制顺序
其中这些BeanPostProcessor
实例通过设置order
财产。
仅当BeanPostProcessor
实现Ordered
接口。如果您编写自己的BeanPostProcessor
,您应该考虑实现
这Ordered
界面也是如此。有关更多详细信息,请参阅BeanPostProcessor
和Ordered
接口。另请参阅有关程序化注册BeanPostProcessor
实例.
要更改实际的 Bean 定义(即定义 Bean 的蓝图),
您需要改用 |
这org.springframework.beans.factory.config.BeanPostProcessor
接口由以下内容组成
恰好有两个回调方法。当此类类注册为后处理器时,具有
容器,对于容器创建的每个 Bean 实例,
后处理器在容器之前从容器获取回调
初始化方法(例如InitializingBean.afterPropertiesSet()
或任何
宣布init
方法),并在任何 bean 初始化回调之后调用。
后处理器可以对 bean 实例执行任何作,包括忽略
回调。bean 后处理器通常检查回调接口,
或者它可以用代理包装 bean。一些 Spring AOP 基础设施类是
作为 bean 后处理器实现,以提供代理包装逻辑。
一ApplicationContext
自动检测在
实现BeanPostProcessor
接口。这ApplicationContext
将这些 bean 注册为后处理器,以便可以调用它们
后来,在 bean 创建时。Bean 后处理器可以部署在容器中的
与任何其他豆子一样。
请注意,当声明BeanPostProcessor
通过使用@Bean
工厂方法
配置类,工厂方法的返回类型应该是实现
类本身或至少org.springframework.beans.factory.config.BeanPostProcessor
接口,清楚地指示该 bean 的后处理器性质。否则,ApplicationContext
在完全创建之前无法按类型自动检测它。
由于BeanPostProcessor
需要尽早实例化才能应用于
在上下文中初始化其他 bean,这种早期类型检测至关重要。
以编程方式注册 虽然推荐的方法BeanPostProcessor 实例BeanPostProcessor 注册是通过ApplicationContext 自动检测(如前所述),您可以注册它们
以编程方式针对ConfigurableBeanFactory 通过使用addBeanPostProcessor 方法。当您需要在之前评估条件逻辑时,这会很有用
注册,甚至用于跨层次结构中的上下文复制 Bean 后处理器。
但请注意,BeanPostProcessor 以编程方式添加的实例不尊重
这Ordered 接口。在这里,是注册顺序决定了顺序
执行。另请注意,BeanPostProcessor 以编程方式注册的实例
始终在通过自动检测注册的
显式排序。 |
BeanPostProcessor 实例和 AOP 自动代理实现 对于任何此类 bean,您应该会看到一条信息日志消息: 如果你有 bean 连接到你的 |
以下示例演示如何编写、注册和使用BeanPostProcessor
实例
在ApplicationContext
.
示例:Hello World,BeanPostProcessor
-风格
第一个示例说明了基本用法。该示例显示了自定义BeanPostProcessor
调用toString()
每个 bean 的方法
它由容器创建,并将生成的字符串打印到系统控制台。
以下列表显示了自定义BeanPostProcessor
实现类定义:
-
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,所以它可以像你一样注入依赖
其他豆子。(前面的配置还定义了一个由 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
,有一个专业
差异:BeanFactoryPostProcessor
对 Bean 配置元数据进行作。
也就是说,Spring IoC 容器允许BeanFactoryPostProcessor
阅读
配置元数据,并可能在容器实例化之前对其进行更改
除BeanFactoryPostProcessor
实例。
您可以配置多个BeanFactoryPostProcessor
实例,您可以控制
这些BeanFactoryPostProcessor
实例通过设置order
财产。
但是,只有在BeanFactoryPostProcessor
实现Ordered
接口。如果您编写自己的BeanFactoryPostProcessor
,你应该
考虑实现Ordered
界面也是如此。请参阅BeanFactoryPostProcessor
和Ordered
接口了解更多详细信息。
如果要更改实际的 bean 实例(即创建的对象
)中,则需要改为 也 |
当 bean 工厂后处理器在ApplicationContext
,以便将更改应用于
定义容器。Spring 包括一些预定义的 bean 工厂
后处理器,例如PropertyOverrideConfigurer
和PropertySourcesPlaceholderConfigurer
.您还可以使用自定义BeanFactoryPostProcessor
- 例如,注册自定义属性编辑器。
一ApplicationContext
自动检测部署到其中的任何 bean
实现BeanFactoryPostProcessor
接口。它使用这些豆子作为豆子工厂
后处理器,在适当的时间。您可以将这些后处理器 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 占位符值被定义:
<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
应用于替换某些属性的元数据DataSource
. 要替换的值被指定为 形式${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',并且这同样适用于与属性文件中的键匹配的其他占位符值。 这PropertySourcesPlaceholderConfigurer
检查大多数属性中的占位符和bean 定义的属性。此外,您可以自定义占位符前缀、suffix、默认值分隔符和转义字符。此外,默认转义字符可以通过设置spring.placeholder.escapeCharacter.default
属性通过 JVM 系统属性(或通过
这SpringProperties
机制)。
使用context
命名空间,您可以配置属性占位符使用专用配置元素。您可以将一个或多个位置作为逗号分隔的列表location
属性,如以下示例所示:
<context:property-placeholder location="classpath:com/something/jdbc.properties"/>
这PropertySourcesPlaceholderConfigurer
不仅在Properties
您指定的文件。默认情况下,如果在指定的属性文件中找不到属性,它会检查 SpringEnvironment
属性和常规 JavaSystem
性能。
只需为给定应用程序定义一个这样的元素,其属性它需要的。可以配置多个属性占位符,只要它们具有不同的占位符语法 ( 如果您需要模块化用于替换的属性源,您应该不要创建多个属性占位符。相反,您应该创建自己的 |
您可以使用
如果该类无法在运行时解析为有效类,则 bean在即将创建时(即在 |
示例:该PropertyOverrideConfigurer
这PropertyOverrideConfigurer
,另一个 bean 工厂后处理器,类似于PropertySourcesPlaceholderConfigurer
,但与后者不同的是,原始定义可以具有 bean 属性的默认值或根本没有值。如果覆盖Properties
file 没有某个 bean 属性的条目,则使用默认的context 定义。
请注意,bean 定义不知道被覆盖,因此它不是从 XML 定义文件中可以立即看出覆盖配置器正在被覆盖 使用。 如果出现多个PropertyOverrideConfigurer
定义不同值的实例,由于覆盖机制,最后一个获胜。
属性文件配置文件行采用以下格式:
beanName.property=value
以下列表显示了格式的示例:
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
此示例文件可以与包含名为dataSource
那有driverClassName
和url
性能。
还支持复合属性名称,只要路径的每个组件除了被覆盖的最终属性已经非 null(大概由构造函数初始化)。在下面的示例中,sammy
属性的bob
属性的fred
属性的tom
bean 设置为标量值123
:
tom.fred.bob.sammy=123
指定的覆盖值始终是文字值。它们不会转换为bean 引用。当 XML bean 中的原始值definition 指定 bean 引用时,此约定也适用。 |
使用context
命名空间,可以在 Spring 2.5 中引入,可以配置属性,使用专用配置元素覆盖,如以下示例所示:
<context:property-override location="classpath:override.properties"/>
使用FactoryBean
您可以实现org.springframework.beans.factory.FactoryBean
对象的接口本身就是工厂。
这FactoryBean
接口是 Spring IoC 容器的实例化逻辑的可插拔性点。如果您有复杂的初始化代码,可以更好地用Java 而不是(可能)冗长的 XML 数量,您可以创建自己的 XMLFactoryBean
,在该类中编写复杂的初始化,然后将 习惯FactoryBean
放入容器中。
这FactoryBean<T>
interface 提供了三种方法:
-
T getObject()
:返回此工厂创建的对象的实例。 这 实例可以共享,具体取决于该工厂是否返回单例或原型。 -
boolean isSingleton()
:返回true
如果这FactoryBean
返回单例或false
否则。 此方法的默认实现返回true
. -
Class<?> getObjectType()
:返回getObject()
方法 或null
如果事先不知道类型。
这FactoryBean
概念和接口在 Spring 中的许多地方都使用了 框架。 超过 50 个实现FactoryBean
与 Spring 一起发布的接口 本身。
当您需要向容器索取实际的FactoryBean
实例本身,而不是它生成的 bean,为 bean 的id
当调用 & 符号 () 时调用&
getBean()
方法ApplicationContext
. 所以,就给定而言FactoryBean
使用id
之myBean
调用getBean("myBean")
返回的FactoryBean
,而调用getBean("&myBean")
返回FactoryBean
实例本身。