BeanFactoryPostProcessor的定义和作用
在这篇Spring源码解析-BeanPostProcessor 文章了解了bean初始化后对其实例的修改,本文则探讨另外一个接口,是bean初始化之前供你修改bean配置数据元(即bean definition)的回调接口。这也是BeanPostProcessor和BeanFactoryPostProcessor的最主要的区别。Application Contexts 能够自动的检测到BeanFactoryPostProcessor beans并被应用于其他bean被实例之前去修改属性。这也很方便我们能够在初始化bean之前对bean做些特殊处理。在Spring里也提供了一组这样的实现类,如:PropertyPlaceholderConfigurer、PropertyOverrideConfigurer 等都是这个接口的实现类,我们也可以自己去实现这个接口,并实现自己的业务逻辑。
BeanFactoryPostProcessor方法
该接口很简单,只有一个方法:
public interface BeanFactoryPostProcessor {
/**
* 实现该方法,去修改bean definition
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
该接口还有个扩展接口,就是BeanDefinitionRegistryPostProcessor,实现这个接口之类,会在BeanFactoryPostProcessor之前就被执行,BeanDefinitionRegistryPostProcessor可以注册更多的bean definition在BeanFactoryPostProcessor调用之前。该接口也只有一个方法:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
/**
* 运行增加更多的bean定义
*/
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
在spring中,我们会用注解的方式代替XML方式来注册bean,我们会在类上面注解Configuration这个注解来注册bean,而这些bean就是通过BeanDefinitionRegistryPostProcessor这个接口来实现注册bean的定义的。具体下面来看下具体的实现到底是怎么做的。
BeanFactoryPostProcessor的实现
PropertyPlaceholderConfigurer的作用就是在实例化bean之前,把bean定义里面的所有的通配符字段替换成配置文件里面配置的值,举个最常见的例子,配置数据源,我们都会用通配符去获取配置文件,如下配置:
spring创建这个bean definition的时候并没有把真正的配置文件里面的值set到属性里面去,这时候就需要BeanFactoryPostProcessor的实现类来去在实例化这个数据源的之前进行通配符的替换,这也就是PropertyPlaceholderConfigurer的工作了,具体怎么替换不展开讲了,自行脑补,具体的实现如下:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertySources == null) {
this.propertySources = new MutablePropertySources();
if (this.environment != null) {
this.propertySources.addLast(
new PropertySource(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
@Override
public String getProperty(String key) {
return this.source.getProperty(key);
}
}
);
}
try {
PropertySource> localPropertySource =
new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
if (this.localOverride) {
this.propertySources.addFirst(localPropertySource);
}
else {
this.propertySources.addLast(localPropertySource);
}
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
this.appliedPropertySources = this.propertySources;
}
该实现业务,就是替换掉${}
这些通配符在bean definition里面。就是在初始化之前去修改bean定义。假如我们要增加更多的bean definition,我们可以用另外一个接口BeanDefinitionRegistryPostProcessor,在Spring中也有这样的实现,如ConfigurationClassPostProcessor,这个类的作用就是自动检测到@Configuration注解的类并解析里面的@Bean方法以及其他的如@Import之类的等等都是这个类来做的,解析是将为这些bean创建bean definition,并注册到容器里面去,就是我们上面说到的,他的作用就是为了注册更多的bean用的。具体代码如下:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
//处理解析并注册bean定义
processConfigBeanDefinitions(registry);
}
具体也不张开将,我们主要明白这两个接口是来干嘛用的就行了。如果有类似的需求,我们可以用这两个接口来扩展我们的业务。
总结
通过对BeanFactoryPostProcessor和BeanPostProcessor对比,两者的区别以及作用,都能够很好的帮助我们在后续的开发工作中更好的写出优雅的代码。Spring提供了很多这种接口方便我们去处理某类业务,像BeanFactoryPostProcessor就是去修改bean definition而BeanPostProcessor是去修改实例化后的对象,这些都是很好的后置处理器。