|
对于最新的稳定版本,请使用 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,这些 bean实现BeanFactoryPostProcessor接口。 它使用这些 bean 作为 bean 工厂后处理器,在适当的时间。您可以将这些后处理器 bean 部署为您将任何其他 bean。
与BeanPostProcessors 时,您通常不想配置BeanFactoryPostProcessors 用于延迟初始化。如果没有其他 bean 引用Bean(Factory)PostProcessor,则该后处理器根本不会被实例化。因此,将其标记为延迟初始化将被忽略,并且Bean(Factory)PostProcessor即使您将default-lazy-init属性设置为true在声明您的<beans />元素。 |
示例:类名替换PropertySourcesPlaceholderConfigurer
您可以使用PropertySourcesPlaceholderConfigurer外部化属性值
使用标准 Java 从单独文件中的 bean 定义Properties格式。
这样做使部署应用程序的人员能够自定义特定于环境的
属性,例如数据库 URL 和密码,而没有复杂性或风险
修改容器的一个或多个主 XML 定义文件。
考虑以下基于 XML 的配置元数据片段,其中DataSourcewith 占位符值被定义:
<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 定义的属性。此外,您可以自定义占位符前缀和后缀。
使用context命名空间,您可以配置属性占位符
具有专用配置元素。您可以将一个或多个位置作为
逗号分隔的列表location属性,如以下示例所示:
<context:property-placeholder location="classpath:com/something/jdbc.properties"/>
这PropertySourcesPlaceholderConfigurer不仅在Properties您指定的文件。默认情况下,如果在指定的属性文件中找不到属性,它会检查 SpringEnvironment属性和常规 JavaSystem性能。
|
只需为给定应用程序定义一个这样的元素,其属性它需要的。可以配置多个属性占位符,只要它们具有不同的占位符语法 ( 如果需要模块化用于替换的属性源,则应
不创建多个属性占位符。相反,您应该创建自己的 |
|
您可以使用
如果该类无法在运行时解析为有效类,则 bean在即将创建时(即在 |
示例:该PropertyOverrideConfigurer
这PropertyOverrideConfigurer,另一个 bean 工厂后处理器,类似于PropertySourcesPlaceholderConfigurer,但与后者不同的是,原始定义可以具有 bean 属性的默认值或根本没有值。如果覆盖Propertiesfile 没有某个 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属性的tombean 设置为标量值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实例本身。