什么是BeanFactoryPostProcessor
在前面的《Spring进阶-BeanPostprocessor》
中说过BeanPostprocessor
主要是用在Bean的创建过程中对其进行扩展的,比如说@PostConstruct
注解的实现原理就是通过BeanPostprocessor
实现的。而这里要说的BeanFactoryPostProcessor
,从名称上来说这两个名称比较相似。而实际上它们的主要作用也比较相似,都是用来为某些过程增加扩展的。不同的在于,BeanPostprocessor
作用的目标为Bean,而BeanFactoryPostProcessor
作用的对象为BeanFactory。通常我们可以用BeanFactoryPostProcessor
来定制和修改BeanFactory的内容,例如覆盖或者添加属性。
接口定义
直接查看Spring源码可以知道,BeanFactoryPostProcessor
只不过是一个接口,该接口的定义如下:
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
接口定义很简单,只有一个方法postProcessBeanFactory
。从源码中的注释我们可以知道,我们可以通过该方法在BeanFactory初始化之后修改程序上下文的内部BeanFactory,而此时的BeanDefinition都已经被加载了,但是Bean并未实例化。同时文档中有提及一点,在该过程中不要进行Bean实例相关交互,这可能导致实例提前创建发生异常情况。
如何使用
通过前面的内容你应该知道BeanFactoryPostProcessor
是什么有什么用了,现在我们通过一个简单的例子来进一步了解。对于如何使用,我们完全可以对照BeanPostprocessor
的来使用。
注册
关于如何注册主要有两种方式,最直白的方式就是通过ConfigurableApplicationContext
提供的addBeanFactoryPostProcessor
方法进行注册,另一种直接在容器中定义即可。
public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) {
Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null");
this.beanFactoryPostProcessors.add(postProcessor);
}
上面就是AbstractApplicationContext
中添加BeanFactoryPostProcessor
的源代码,简单来说就是在内部使用List来存储注册的BeanFactoryPostProcessor
。上面说过还有另外一种方式,该方式是直接在配置中定义一个BeanFactoryPostProcessor
,容器会自动注册进来。这部分源码我们可以通过AbstractApplicationContext#refresh
方法找到如何实现。该方法内部调用了如下代码:
invokeBeanFactoryPostProcessors(beanFactory);
该方法的内部主要实现则封装在该方法中:
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
getBeanFactoryPostProcessors
方法返回的就是beanFactoryPostProcessors
这个List中的内容,而invokeBeanFactoryPostProcessors
方法的内部主要实现如下:
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
//存储处理完的BeanFactoryPostProcessor
Set<String> processedBeans = new HashSet<>();
//处理BeanDefinitionRegistryPostProcessor(BeanFactoryPostProcessor子接口)
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
//存储常规的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//存储BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//遍历入参传入的BeanFactoryPostProcessor并添加到regularPostProcessors或者registryProcessors中
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
//临时变量
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 处理实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//排序并添加到列表
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
//执行postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清除临时变量
currentRegistryProcessors.clear();
// 处理实现了Ordered的BeanDefinitionRegistryPostProcessors
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 处理剩下的BeanDefinitionRegistryPostProcessors直到不再出现
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// 执行BeanFactoryPostProcessor#方法postProcessBeanFactory
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// Invoke factory processors registered with the context instance.
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// 获取所有的BeanFactoryPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
//存储实现了PriorityOrdered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
//存储实现了Ordered接口的BeanFactoryPostProcessor
List<String> orderedPostProcessorNames = new ArrayList<>();
//存储没有实现任何排序相关接口的BeanFactoryPostProcessor
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// 跳过之前处理过的
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 排序并执行实现了PriorityOrdered接口的BeanFactoryPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 排序并执行实现了Ordered接口的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 执行剩下的BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
beanFactory.clearMetadataCache();
}
从上面源码我们可以看出,我们即使不调用手动addBeanFactoryPostProcessor
方法注册BeanFactoryPostProcessor
也是可以应用的。从上面的源码中我们可以了解到,BeanFactoryPostProcessor执行是有顺序的。
实现BeanFactoryPostProcessor接口
通过前面我们知道了如何把BeanFactoryPostProcessor
注册到容器中了,接下来就是如何使用了。使用BeanFactoryPostProcessor
时我们需要特别注意的一点是,与我们交互的是BeanDefinition
而不是Bean实例。例如现在我们有个需求是将BeanDefinition中的属性值由小写转成大写,这时候我们就可以使用BeanFactoryPostProcessor
来完成。
public class App1 {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-bfp.xml");
System.out.println("打印BeanDefinition");
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("user");
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues) {
System.out.println(propertyValue.getName() + " => " + propertyValue.getValue());
}
System.out.println("打印实例");
User user = context.getBean("user", User.class);
System.out.println(user);
}
}
class MyBeanFactoryPostprocessor implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinition user = beanFactory.getBeanDefinition("user");
MutablePropertyValues propertyValues = user.getPropertyValues();
for (PropertyValue propertyValue : propertyValues) {
if (propertyValue.getValue() instanceof TypedStringValue){
TypedStringValue value = (TypedStringValue) propertyValue.getValue();
if (StringUtils.hasText(value.getValue())){
value.setValue(value.getValue().toUpperCase(Locale.ROOT));
}
}
}
}
}
@Data
class User{
private String firstName;
private String lastName;
}
spring-bfp.xml
配置文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.buydeem.share.beanfactorypostprocessor.User">
<property name="firstName" value="mac"/>
<property name="lastName" value="jodn"/>
</bean>
<bean id="myBeanFactoryPostprocessor" class="com.buydeem.share.beanfactorypostprocessor.MyBeanFactoryPostprocessor"/>
</beans>
在配置文件中我们定义了两个Bean,其中user
我们设置它的属性名字都是小写字母,而myBeanFactoryPostprocessor
作为BeanFactoryPostprocessor
它会自动注册到容器中,运行代码打印结果如下:
打印BeanDefinition
firstName => TypedStringValue: value [MAC], target type [null]
lastName => TypedStringValue: value [JODN], target type [null]
打印实例
User(firstName=MAC, lastName=JODN)
从运行结果可以看出,BeanDefinition中的属性值并转成了大写,这也导致了后续创建出来的实例它的属性值也变成了大写。
PropertySourcesPlaceholderConfigurer
在Spring中我们可以使用${...}
的形式将properties文件中的配置替换,通常我们可以通过<property-placeholder/>
来完成。如下所示:
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="user" class="com.buydeem.share.beanfactorypostprocessor.User">
<property name="firstName" value="${firstName}"/>
<property name="lastName" value="${lastName}"/>
</bean>
<context:property-placeholder location="user.properties"/>
</beans>
实际上该标签的实现核心之一就是需要BeanFactoryPostprocessor
来完成。其实我们不使用这个标签,可以使用如下配置实现相同的功能。
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="classpath:user.properties"/>
</bean>
可能现在你还是一脸疑惑,为啥能实现${...}
替换功能?我们先看一下PropertySourcesPlaceholderConfigurer
结构。

从上图可以看出PropertySourcesPlaceholderConfigurer
它间接的实现了BeanFactoryPostprocessor
接口,而前面我们的例子中我们可以通过BeanFactoryPostprocessor
来更新XML中定义的BeanDefinition,而PropertySourcesPlaceholderConfigurer
的实现原理也一样。同样是通过实现postProcessBeanFactory
方法来替换掉${...}
中的内容。
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>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
@Override
@Nullable
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);
}
}
//处理properties,${...}替换的主要逻辑
processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
this.appliedPropertySources = this.propertySources;
}
BeanDefinitionRegistryPostProcessor
BeanFactoryPostprocessor
还有一个子接口BeanDefinitionRegistryPostProcessor
,该接口的定义如下:
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
该接口只有一个方法,该方法提供的一个BeanDefinitionRegistry
类型的参数,而BeanDefinitionRegistry
提供了管理BeanDefinition的功能。例如提供了BeanDefinition注册的功能。那这个接口有啥用?例如我们可以通过该接口动态的添加BeanDefinition,废话不多说直接看示例:
public class App3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App3.class);
Person person = context.getBean("person", Person.class);
System.out.println(person);
}
@Bean
public MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor(){
return new MyBeanDefinitionRegistryPostProcessor();
}
}
class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor{
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(Person.class)
.addPropertyValue("name", "mac")
.getBeanDefinition();
registry.registerBeanDefinition("person",definition);
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
@Data
class Person{
private String name;
}
上面的示例代码中,我们实现了BeanDefinitionRegistryPostProcessor
中的postProcessBeanDefinitionRegistry
方法,然后在该方法中添加了一个BeanDefinition。运行代码最后的打印结果如下:
Person(name=mac)
通常我们定义BeanDefinition之后再将它们添加到IOC容器,而常用的方式都是通过注解或者XML。而通过BeanDefinitionRegistryPostProcessor
我们可以实现动态的将BeanDefinition添加到IOC容器中。
现在我们使用Spring几乎很少使用XML来定义BeanDefinition了,更多的是通过JavaConfig形式来完成,特别是在SpringBoot中这点更加明显。通常我们会使用到@Configuration
、@Bean
等注解,这些注解的实现都是通过BeanDefinitionRegistryPostProcessor
来实现的。关于实现的细节部分这里就不多说了,后续如果有时间再细说,有兴趣的也可以自己去看看。
小结
看完上面的内容,我认为你应该至少知道了一下几点:
-
什么是 BeanFactoryPostprocessor
以及它的作用 -
了解如何自定义 BeanFactoryPostprocessor
-
PropertySourcesPlaceholderConfigurer
实现的基本原理 -
BeanDefinitionRegistryPostProcessor
接口的作用以及用法
原文始发于微信公众号(一只菜鸟程序员):Spring进阶-BeanFactoryPostprocessor
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/72960.html