spring官网是这样描述BeanFactoryPostProcessor
的:
BeanFactoryPostProcessor
可以对Bean配置元数据进行操作,也就是说,spring容器允许BeanFactoryPostProcessor
读取指定Bean的配置元数据,并可以在Bean被实例化前修改它,这个的配置元数据就是BeanDefination
。- 我们可以配置多个
BeanFactoryPostProcessor
,并且只要我们配置的BeanFactoryPostProcessor
实现了Ordered
接口的话,我么还可以控制这些BeanFactoryPostProcessor
的执行顺序。
eg:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<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
Ordered
用于决定执行顺序;PriorityOrdered
这个接口直接继承Ordered
接口,并且没有做任何扩展,只是作为一个标记接口,也用于决定BeanFactoryPortProcessor
的执行顺序。Aware
;FunctionalInterface
这是java8新增的一个接口,也是一个标记接口,标记该接口是一个函数式接口;BeanFactoryPortProcessor
代表这个类是一个Bean工厂的后置处理器;PropertiesLoaderSupport
这个类主要包含定义了属性的加载方法,包含属性如下:
// 本地属性,可以直接在XML中配置
@Nullable
protected Properties[] localProperties;
// 是否用本地的属性覆盖提供的文件中的属性,默认不会
protected boolean localOverride = false;
// 根据地址找到的对应文件
@Nullable
private Resource[] locations;
// 没有找到对应文件是否抛出异常,false代表不抛出
private boolean ignoreResourceNotFound = false;
// 对应文件资源的编码
@Nullable
private String fileEncoding;
// 文件解析器
private PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
PropertyResourceConfigurer
这个类主要可以对读取到的属性进行一些转换;PlaceholderConfigurerSupport
主要负责对占位符进行解析,其中属性如下:
// 默认解析的前缀
public static final String DEFAULT_PLACEHOLDER_PREFIX = "${";
// 默认解析的后缀
public static final String DEFAULT_PLACEHOLDER_SUFFIX = "}";
// 属性名称跟属性值的分隔符
public static final String DEFAULT_VALUE_SEPARATOR = ":";
PropertyPlaceholderConfigurer
继承上面这些类的所有功能,同时可以配置属性的解析顺序;
// 不在系统属性中查找
public static final int SYSTEM_PROPERTIES_MODE_NEVER = 0;
// 如果在配置文件中没有找到,再去系统属性中查找
public static final int SYSTEM_PROPERTIES_MODE_FALLBACK = 1;
// 先查找系统属性,没查到再去查找配置文件中的属性
public static final int SYSTEM_PROPERTIES_MODE_OVERRIDE = 2;
如何将jdbc.properties文件中的属性值应用到BasicDtaSource这个Bean上
PropertyPlaceholdConfigurer
这个特殊的BeanFactoryPostProcessor
完成了BeanDefinition
中的属性值中的占位符的替换,在BeanDefinition
被解析出来后,bean实例化之前对其进行了更改。
spring是如何扫描并解析成BeanDefinition
的?
BeanDefinitionRegistryPostProcessor
- 直接继承
BeanFactoryPostProcessor
,所以是一个Bean工厂后置处理器; - 实现类
ConfigurationClassPostProcessor
,扫描解析Bean就是由这个类完成的;
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
相比于正常的BeanFactoryPostProcessor
,BeanDefinitionRegistryPostProcessor
多提供了一个方法,这个方法相比于父类的postProcessBeanFactory
方法更加靠前执行,所以spring利用这个特性来完成扫描。
执行流程源码解析
BeanDefinitionRegistryPostProcessor
执行流程
在使用postProcessBeanFactory
这个方法时,所有的BeanDefinition
都已经被加载,而postProcessBeanDefinitionRegistry
允许我们在下一个后置处理器执行前添加更多的BeanDefinition
,所以后者的执行时机早于前者;
总结如下:
- 先执行直接实现了
BeanDefinitionRegistryPostProcessor
接口的后置处理器,所有实现了BeanDefinitionRegistryPostProcessor
接口的类有两个方法,一个是特有的postProcessBeanDefinitionRegistry
方法,一个是继承子父接口的postProcessBeanFactory
方法。-
postProcessBeanDefinitionRegistry
方法早于postProcessBeanFactory
方法执行,对于postProcessBeanDefinitionRegistry
的执行顺序又遵循如下原子- ⅰ. 先执行实现了
PriorityOrdered
接口的类中的postProcessBeanDefinitionRegistry
方法 - ⅱ. 再执行实现了
Ordered
接口的类中的postProcessBeanDefinitionRegistry
的方法 - ⅲ. 最后执行没有实现上面两个接口的类中的
postProcessBeanDefinitionRegistry
的方法
- ⅰ. 先执行实现了
-
执行完所有的
postProcessBeanDefinitionRegistry
方法后,再执行实现了BeanDefinitionRegistryPostProcessor
接口的类中的postProcessBeanFactory
方法
-
- 再执行直接实现了
BeanFactoryPostProcessor
接口的后置处理器
a. 先执行实现了PriorityOrdered
接口的类中的postProcessBeanFactory
方法
b. 再执行实现了Ordered
接口的类中的postProcessBeanFactory
的方法
c. 最后执行没有实现上面两个接口的类中的postProcessBeanFactory
的方法.