Spring生命周期之【BeanFactoryPostProcessor】

161 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情

前言

Spring生命周期中,BeanFactoryPostProcessor应该算是我们使用得比较少的一个扩展点了,为了对这个扩展点更加熟悉,我们特地通过这篇文章来整理一下相关的知识点;

作用

我们都知道Spring Bean的实例化都是依据BeanDefinition配置的,我们这篇文章讲述的BeanFactoryPostProcessor就是作用的BeanDefinition上的,它可以在容器实例化任何Bean之前读取到BeanDefinition,并通过修改它来影响Bean的实例化;

示例

我们通过代码来验证一下BeanFactoryPostProcessor是不是真的能够修改BeanDefinition

我们先创建一个配置类:

@Data
@Configuration
@ConfigurationProperties(prefix = "person")
public class PersonProperties {
private String name;
private int age;
}

这个配置类本来是可以从application.yml中读取配置数据的;假如我们不从application.yml中读取配置,而是通过BeanFactoryPostProcessor来动态设置里面的nameage值;那么我们可以自己来实现一个自定义的BeanFactoryPostProcessor

import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
​
/**
* @author zouwei
* @className CustomBeanFactoryPostProcessor
* @date: 2022/12/13 21:28
* @description:
*/
@Component
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
   // 获取所有bean的名称
String[] names = beanFactory.getBeanDefinitionNames();
for (String name : names) {
     // 如果bean名称符合我们拦截的条件
if ("personProperties".equals(name)) {
       // 获取其中的BeanDefinition
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
       // 设置里面的两个属性name和age
MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
       // name设置为zouwei
       propertyValues.add("name""zouwei");
       // age设置为30
       propertyValues.add("age"30);
}
}
}
}

下面我们通过Controller来做一个简单的测试:

@Autowired
private PersonProperties properties;
​
@GetMapping("/getProperties")
public Map getProperties() {
Map result = new HashMap();
result.put("name", properties.getName());
result.put("age", properties.getAge());
return result;
}

最终我们可以从返回的结果中看到:

{
 code200,
 data: {
   name: "zouwei",
   age: 30
},
 message: "",
 error: "",
 metaInfo: null
}

我们确实从最终的返回值中得到了nameage,并且它就是我们在自定义BeanFactoryPostProcessor中设置好的;

应用

Spring配置文件中,我们经常会使用到如下配置:

image-20221213222205683.png

bucket-name的配置值引用了spring.application.name的值,这个功能的实现其实归功于PropertyPlaceholderConfigurer.class,它也是BeanFactoryPostProcessor子类;

再比如AbstractDependsOnBeanFactoryPostProcessor,它实现了BeanBean之间的依赖关系,它可以动态地配置某个Bean在进行初始化之前必须等待一些特定的Bean准备好;