通常,应用程序开发人员不需要对实现类进行子类化。相反,可以通过插入来扩展 Spring IoC 容器
特殊集成接口的实现。接下来的几节将介绍这些内容
集成接口。ApplicationContext
使用BeanPostProcessor
该接口定义了可以实现的回调方法
提供你自己的(或覆盖容器的默认)实例化逻辑、依赖关系
解析逻辑等。如果要在
Spring 容器完成 Bean 的实例化、配置和初始化,可以
插入一个或多个自定义实现。BeanPostProcessor
BeanPostProcessor
您可以配置多个实例,并且可以控制顺序
通过设置属性来运行这些实例。
仅当实现接口时,才能设置此属性。如果你自己编写,你应该考虑实现
界面也是如此。有关更多详细信息,请参阅 BeanPostProcessor
和 Ordered
接口的 javadoc。另请参阅有关 BeanPostProcessor
实例的编程注册的说明。BeanPostProcessor
BeanPostProcessor
order
BeanPostProcessor
Ordered
BeanPostProcessor
Ordered
要更改实际的 Bean 定义(即定义 Bean 的蓝图),
您需要改用 ,如使用 |
该接口包括
正好是两个回调方法。当这样的类被注册为后处理器时
容器,对于容器创建的每个 Bean 实例,
后处理器在容器之前从容器获取回调
初始化方法(如 或任何
声明的方法)被调用,并在任何 Bean 初始化回调之后。
后处理器可以对 Bean 实例执行任何操作,包括忽略
完全回调。Bean 后处理器通常检查回调接口,
或者它可能用代理包装 bean。一些 Spring AOP 基础结构类是
作为 Bean 后处理器实现,以提供代理包装逻辑。org.springframework.beans.factory.config.BeanPostProcessor
InitializingBean.afterPropertiesSet()
init
一个自动检测
实现接口的配置元数据。将这些 Bean 注册为后处理器,以便可以调用它们
后来,在豆子创造时。Bean 后处理器可以部署在容器中的
与任何其他豆子相同的时尚。ApplicationContext
BeanPostProcessor
ApplicationContext
请注意,当在
配置类,工厂方法的返回类型应该是实现
类本身或至少是接口,清楚地表明该 Bean 的后处理器性质。否则,在完全创建它之前,无法按类型自动检测它。
由于 a 需要尽早实例化才能应用于
在上下文中初始化其他 Bean,这种早期类型检测至关重要。BeanPostProcessor
@Bean
org.springframework.beans.factory.config.BeanPostProcessor
ApplicationContext
BeanPostProcessor
以编程方式注册实例 虽然推荐的注册方法是通过自动检测(如前所述),但您可以注册它们
使用该方法以编程方式针对 A。当您需要在之前评估条件逻辑时,这可能很有用
注册,甚至用于在层次结构中跨上下文复制 Bean 后处理器。
但请注意,以编程方式添加的实例不遵守
接口。在这里,注册顺序决定了顺序
的执行。另请注意,以编程方式注册的实例
始终在通过自动检测注册之前进行处理,无论是否有任何
显式排序。BeanPostProcessor BeanPostProcessor ApplicationContext ConfigurableBeanFactory addBeanPostProcessor BeanPostProcessor Ordered BeanPostProcessor |
BeanPostProcessor 实例和 AOP 自动代理实现接口的类是特殊的,并经过处理
因容器而异。所有实例和 bean 他们
直接引用在启动时实例化,作为特殊启动阶段的一部分
的 .接下来,注册所有实例
以分类方式应用于容器中的所有其他豆子。因为AOP
自动代理是作为自身实现的,实例和它们直接引用的 Bean 都不符合自动代理的条件,并且,
因此,不要将方面编织到其中。 对于任何此类 Bean,您都应该看到一条信息日志消息:。 如果您使用自动接线或(可能会回退到自动接线)将 bean 连接到您的 bean,Spring 可能会访问意外的 bean
在搜索类型匹配的依赖项候选项时,因此,使它们
不符合自动代理或其他类型的 Bean 后处理条件。例如,如果您
有一个依赖项,其中字段或 setter 名称没有
直接对应一个 Bean 的声明名称,不使用 name 属性,
Spring 访问其他 Bean 以按类型匹配它们。 |
以下示例说明如何编写、注册和使用实例
在 .BeanPostProcessor
ApplicationContext
示例:Hello World、-styleBeanPostProcessor
第一个示例说明了基本用法。该示例显示了一个自定义实现,该实现将每个 Bean 的方法调用为
它由容器创建,并将生成的字符串打印到系统控制台。BeanPostProcessor
toString()
下面的清单显示了自定义实现类定义: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>
请注意 是如何定义的。它没有
甚至有一个名字,而且,因为它是一个 bean,所以它可以像任何 bean 一样注入依赖关系
其他豆子。(前面的配置还定义了一个由 Groovy 支持的 Bean
脚本。Spring 动态语言支持在标题为“动态语言支持”的章节中进行了详细介绍。InstantiationTracingBeanPostProcessor
以下 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
我们看的下一个扩展点是 .语义
此接口类似于 的接口,具有一个主要
差异:对 Bean 配置元数据进行操作。
也就是说,Spring IoC 容器允许读取
配置元数据,并可能在容器实例化之前对其进行更改
除实例以外的任何 Bean。org.springframework.beans.factory.config.BeanFactoryPostProcessor
BeanPostProcessor
BeanFactoryPostProcessor
BeanFactoryPostProcessor
BeanFactoryPostProcessor
您可以配置多个实例,并且可以控制
这些实例通过设置属性来运行。
但是,只有在实现接口时才能设置此属性。如果你自己写,你应该
也可以考虑实现该接口。有关更多详细信息,请参阅 BeanFactoryPostProcessor
和 Ordered
接口的 javadoc。BeanFactoryPostProcessor
BeanFactoryPostProcessor
order
BeanFactoryPostProcessor
Ordered
BeanFactoryPostProcessor
Ordered
如果要更改实际的 Bean 实例(即创建的对象
),那么你就需要使用 (在前面的 Customizing 此外,实例的范围是按容器划分的。这是唯一的相关
如果使用容器层次结构。如果将
container,它仅应用于该容器中的 Bean 定义。Bean 定义
在一个容器中不会被另一个容器中的实例进行后处理
容器,即使两个容器都属于同一层次结构。 |
当 bean factory 后处理器在 中声明时,它会自动运行,以便将更改应用于
定义容器。Spring 包含多个预定义的 Bean 工厂
后处理器,例如 和 .您还可以使用自定义 — 例如,注册自定义属性编辑器。ApplicationContext
PropertyOverrideConfigurer
PropertySourcesPlaceholderConfigurer
BeanFactoryPostProcessor
一个自动检测部署到其中的任何 Bean
实现接口。它使用这些豆子作为豆子工厂
后处理器,在适当的时间。您可以将这些后处理器 Bean 部署为
你会任何其他豆子。ApplicationContext
BeanFactoryPostProcessor
与 s 一样,您通常不希望将 s 配置为延迟初始化。如果没有其他 Bean 引用 ,则该后处理器将根本不会被实例化。
因此,将其标记为延迟初始化将被忽略,即使您在元素的声明上将属性设置为 也会急切地实例化。BeanPostProcessor BeanFactoryPostProcessor Bean(Factory)PostProcessor Bean(Factory)PostProcessor default-lazy-init true <beans /> |
示例:类名替换PropertySourcesPlaceholderConfigurer
可以使用 将属性值外部化
使用标准 Java 格式从单独文件中的 Bean 定义。
这样做使部署应用程序的人员能够自定义特定于环境的
属性,例如数据库 URL 和密码,而没有复杂性或风险
修改容器的一个或多个主 XML 定义文件。PropertySourcesPlaceholderConfigurer
Properties
请考虑以下基于 XML 的配置元数据片段,其中定义了具有占位符值的片段:DataSource
<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>
该示例显示了从外部文件配置的属性。在运行时,
a 应用于替换某些
DataSource 的属性。要替换的值被指定为
form ,它遵循 Ant 和 log4j 以及 JSP EL 样式。Properties
PropertySourcesPlaceholderConfigurer
${property-name}
实际值来自标准 Java 格式的另一个文件:Properties
jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
因此,字符串在运行时将替换为值“sa”和
这同样适用于与属性文件中的键匹配的其他占位符值。
对大多数属性中的占位符的检查,以及
Bean 定义的属性。此外,您可以自定义占位符前缀和后缀。${jdbc.username}
PropertySourcesPlaceholderConfigurer
使用 Spring 2.5 中引入的命名空间,您可以配置属性占位符
具有专用配置元素。您可以提供一个或多个位置作为
属性中的逗号分隔列表,如以下示例所示:context
location
<context:property-placeholder location="classpath:com/something/jdbc.properties"/>
不仅在指定的文件中查找属性。默认情况下,如果它在指定的属性文件中找不到属性,
它根据 Spring 属性和常规 Java 属性进行检查。PropertySourcesPlaceholderConfigurer
Properties
Environment
System
对于具有以下属性的给定应用程序,只应定义一个这样的元素
它需要的。可以配置多个属性占位符,只要它们具有不同的
占位符语法 ()。 如果需要模块化用于替换的属性源,则应
不创建多个属性占位符。相反,您应该创建自己的 Bean 来收集要使用的属性。 |
您可以使用 来替换类名,这
当您必须在运行时选择特定的实现类时,有时很有用。
以下示例演示如何执行此操作:
如果在运行时无法将类解析为有效的类,则解析 Bean
当它即将被创建时失败,这是在非惰性初始化 Bean 的阶段。 |
示例:PropertyOverrideConfigurer
另一个 bean factory 后处理器类似于 ,但与后者不同的是,原始定义
Bean 属性可以有缺省值,也可以根本没有值。如果覆盖文件没有某个 bean 属性的条目,那么默认
使用上下文定义。PropertyOverrideConfigurer
PropertySourcesPlaceholderConfigurer
Properties
请注意,bean 定义不知道被覆盖,因此它不会
从 XML 定义文件中可以立即明显看出覆盖配置程序正在
使用。如果多个实例定义不同
由于覆盖机制,同一 Bean 属性的值(最后一个属性获胜)的值。PropertyOverrideConfigurer
属性文件配置行采用以下格式:
beanName.property=value
以下列表显示了该格式的示例:
dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
此示例文件可用于容器定义,该容器定义包含名为 has 和 properties 的 Bean。dataSource
driver
url
还支持复合属性名称,只要路径的每个组件
除了被覆盖的最终属性已经是非 null (大概是初始化的
由构造函数)。在下面的示例中,bean 属性的属性的属性设置为标量值:sammy
bob
fred
tom
123
tom.fred.bob.sammy=123
指定的替代值始终是文本值。它们没有被翻译成 Bean 引用。当 XML Bean 中的原始值 definition 指定 Bean 引用。 |
使用 Spring 2.5 中引入的命名空间,可以配置
使用专用配置元素重写属性,如以下示例所示:context
<context:property-override location="classpath:override.properties"/>
使用FactoryBean
您可以为以下对象实现接口
本身就是工厂。org.springframework.beans.factory.FactoryBean
该接口是可插入Spring IoC容器的一个点
实例化逻辑。如果您有复杂的初始化代码,最好用
Java 与(可能)冗长的 XML 相对,您可以创建自己的 XML,在该类中编写复杂的初始化,然后插入
自定义到容器中。FactoryBean
FactoryBean
FactoryBean
该接口提供三种方法:FactoryBean<T>
-
T getObject()
:返回此工厂创建的对象的实例。这 实例可能是共享的,具体取决于此工厂是否返回单例 或原型。 -
boolean isSingleton()
:如果返回单例或其他方式,则返回。此方法的默认实现返回 。true
FactoryBean
false
true
-
Class<?> getObjectType()
:返回方法返回的对象类型 或者如果事先不知道类型。getObject()
null
这个概念和界面在Spring的许多地方都有使用
框架。Spring 附带了 50 多个接口实现
本身。FactoryBean
FactoryBean
当您需要向容器请求实际实例本身而不是
它生成的 Bean,当
调用 .因此,对于给定的 ,调用容器将返回
的乘积,而 invocationing 返回实例本身。FactoryBean
id
&
getBean()
ApplicationContext
FactoryBean
id
myBean
getBean("myBean")
FactoryBean
getBean("&myBean")
FactoryBean