开启掘金成长之旅!这是我参与「掘金日新计划 · 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
来动态设置里面的name
和age
值;那么我们可以自己来实现一个自定义的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;
}
最终我们可以从返回的结果中看到:
{
code: 200,
data: {
name: "zouwei",
age: 30
},
message: "",
error: "",
metaInfo: null
}
我们确实从最终的返回值中得到了name
和age
,并且它就是我们在自定义BeanFactoryPostProcessor
中设置好的;
应用
在Spring
配置文件中,我们经常会使用到如下配置:
bucket-name
的配置值引用了spring.application.name
的值,这个功能的实现其实归功于PropertyPlaceholderConfigurer.class
,它也是BeanFactoryPostProcessor
子类;
再比如AbstractDependsOnBeanFactoryPostProcessor
,它实现了Bean
与Bean
之间的依赖关系,它可以动态地配置某个Bean
在进行初始化之前必须等待一些特定的Bean
准备好;