这篇文章中容器的扩展指的是向容器提供接口的实现,在容器原有的设计下实现额外的功能。
BeanPostProcessor
BeanPostProcessor
是一个用来定义 bean 的初始化逻辑,依赖解析(确定一个依赖)的逻辑等的接口(使用回调实现),在容器构造出 bean 实例之后(执行初始化回调之前), BeanPostProcessor
可以获取到 bean 实例进行操作。这意味着无法通过 BeanPostProcessor
对 bean 的定义元信息做出更改,实际上这是由 BeanFactoryProcessor
完成的。
在容器中使用多个 BeanPostProcessor
时,可以实现 Order
接口,定义不同的 BeanPostProcessor
的处理顺序。
实现 BeanPostProcessor
可以定义两个分别在 bean 的初始化回调之前和之后的回调,用于修改 bean 实例,在许多情况下, BeanPostProcessor
被用来检查 bean 的回调接口,以及为 bean 实例创建其代理(一些 AOP 就在 BeanPostProcessor
中实现代理)。具体的定义如下:
inteface BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {}
public Object postProcessAfterInitialization(Object bean, String beanName) {}
}
容器中 BeanPostProcessor
的注册是自动的,定义一个 BeanPostProcessor
与定义一个普通的 bean 没有区别。需要注意的是,如果以工厂方法的形式定义 BeanPostProcessor
需要指明返回类型。容器主动发现 BeanPostProcessor
并注册实在 bean 的实例化之前,此时无法通过反射获取类的具体信息,需要在返回值中明确这是一个 BeanPostProcessor
。除了依靠容器自动发现意外,可以使用
容器的 addBeanPostProcessor
方法以代码调用的方式手动注册一个 BeanPostProcessor
,具体来说是 ConfigurableBeanFactory
接口中的方法。
注意 BeanPostProcessor
中定义的依赖对象是没法得到其余 BeanPostProcessor
的处理,自动注入会出现问题(比如没法通过 bean 名称解析,bean 名称在构造 BeanPostProcessor
时还没有指定)。
spring 中对自动注入注解的处理就是使用一个实现了 BeanPostProcessor
的 AutowiredAnnotationBeanPostProcessor
实现的。
BeanFactoryPostProcessor
BeanFactoryPostProcessor
的工作逻辑大致与上文提到的 BeanPostProcessor
相同,区别在于操作的对象变成了 bean 的定义元信息(spring 中对 xml 和 java 定义 bean 的信息的抽象)。
spring 中使用使用配置文件和占位符注入 bean 属性就是利用 BeanFactoryPostProcessor
实现的,具体来说是 PropertySourcesPlaceholderConfigurer
。举个例子:
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="locations" value="classpath:com/something/jdbc.properties"/>
</bean>
<bean id="dataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<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>
jdbc.properties
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
PropertySourcesPlaceholderConfigurer
除了指定的配置文件外,还可以从 string Environment
以及 Java 的 System
中读取环境变量。甚至可以用来指定 Bean 定义的类型(xml 中 bean 元素的 class 属性),在非懒加载的情况下,bean 类型的解析是在容器( ApplicationContext
)的PropertySourcesPlaceholderConfigurer
进行的。
类似的还有 PropertyOverrideConfigurer
实现 bean 配置信息的覆盖。
FactoryBean
在一个 bean 通过 spring 定义难以构建时,可以选择自己实现 FactoryBean
(自身是容器中的工厂 bean ,同时给容器返回一个 bean )。 FactoryBean
支持泛型,使用 T getObject()
, boolean isSingleton()
, Class<?> getObjectType()
来确定所返回的 bean 的实例,作用范围,和类型。当你需要获取这个 FactoryBean 本身,使用 getBean("&beanName")
,beanName 是这个 FactoryBean 返回的 bean 的名称。