BeanFactoryBeanPostProcessor 源码分析

BeanFactoryBeanPostProcessor 是当 BeanDefinition 读取完元数据(也就是从任意资源中定义的 bean 数据)后还未实例化之前可以进行修改

抄录并翻译官方的语句

BeanFactoryPostProcessor 操作 bean 的元数据配置. 也就是说,Spring IoC 容器允许 BeanFactoryPostProcessor 读取配置元数据, 并可能在容器实例化除 BeanFactoryPostProcessor 实例之外的任何 bean 之前 更改它

tip:

BeanFactoryPostProcessor (例如使用 BeanFactory.getBean()) 中使用这些 bean 的实例虽然在技术上是可行的,但这么来做会将 bean 过早实例化, 这违反了标准的容器生命周期. 同时也会引发一些副作用,例如绕过 bean 的后置处理。

  1. public interface BeanFactoryPostProcessor {
  2. /**
  3. *通过ConfigurableListableBeanFactory这个可配置的BeanFactory对我们的bean原数据进行修改
  4. */
  5. void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
  6. }

BeanFactoryPostProcessor 执行时期的探究

ApplicationContext 的 refresh() 中的 invokeBeanFactoryPostProcessors 方法就开始创建我们的 BFPP(BeanFactoryPostProcessor)了

具体执行方法 invokeBeanFactoryPostProcessors,虽然一百多行代码,其实只需要特别了解的地方就几处。

  1. public static void invokeBeanFactoryPostProcessors(
  2. ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
  3. Set<String> processedBeans = new HashSet<>();
  4. // 由于我们的beanFactory是DefaultListableBeanFactory实例是BeanDefinitionRegistry的子类所以可以进来
  5. if (beanFactory instanceof BeanDefinitionRegistry) {
  6. BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
  7. List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
  8. List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
  9. for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
  10. if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
  11. BeanDefinitionRegistryPostProcessor registryProcessor =
  12. (BeanDefinitionRegistryPostProcessor) postProcessor;
  13. registryProcessor.postProcessBeanDefinitionRegistry(registry);
  14. registryProcessors.add(registryProcessor);
  15. }
  16. else {
  17. regularPostProcessors.add(postProcessor);
  18. }
  19. }
  20. // BeanDefinitionRegistryPostProcessor是BFPP的子类但是比BFPP提前执行
  21. // 顺序实现PriorityOrdered接口先被执行,然后是Ordered接口,最后是什么都没实现的BeanDefinitionRegistryPostProcessor
  22. /**
  23. *都有beanFactory.getBean方法,证明BeanDefinitionRegistryPostProcessor这个bean现在已经被创建了
  24. */
  25. List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
  26. String[] postProcessorNames =
  27. beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  28. for (String ppName : postProcessorNames) {
  29. if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
  30. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  31. processedBeans.add(ppName);
  32. }
  33. }
  34. sortPostProcessors(currentRegistryProcessors, beanFactory);
  35. registryProcessors.addAll(currentRegistryProcessors);
  36. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
  37. currentRegistryProcessors.clear();
  38. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  39. for (String ppName : postProcessorNames) {
  40. if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
  41. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  42. processedBeans.add(ppName);
  43. }
  44. }
  45. sortPostProcessors(currentRegistryProcessors, beanFactory);
  46. registryProcessors.addAll(currentRegistryProcessors);
  47. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
  48. currentRegistryProcessors.clear();
  49. boolean reiterate = true;
  50. while (reiterate) {
  51. reiterate = false;
  52. postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  53. for (String ppName : postProcessorNames) {
  54. if (!processedBeans.contains(ppName)) {
  55. currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  56. processedBeans.add(ppName);
  57. reiterate = true;
  58. }
  59. }
  60. sortPostProcessors(currentRegistryProcessors, beanFactory);
  61. registryProcessors.addAll(currentRegistryProcessors);
  62. invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
  63. currentRegistryProcessors.clear();
  64. }
  65. invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
  66. invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
  67. }
  68. else {
  69. invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
  70. }
  71. // BFPP的执行顺序与上一样
  72. /**
  73. *都有beanFactory.getBean方法,证明BFPP这个bean现在已经被创建了
  74. */
  75. String[] postProcessorNames =
  76. beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
  77. List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
  78. List<String> orderedPostProcessorNames = new ArrayList<>();
  79. List<String> nonOrderedPostProcessorNames = new ArrayList<>();
  80. for (String ppName : postProcessorNames) {
  81. if (processedBeans.contains(ppName)) {
  82. }
  83. else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
  84. priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
  85. }
  86. else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
  87. orderedPostProcessorNames.add(ppName);
  88. }
  89. else {
  90. nonOrderedPostProcessorNames.add(ppName);
  91. }
  92. }
  93. sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
  94. invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
  95. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
  96. for (String postProcessorName : orderedPostProcessorNames) {
  97. orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
  98. }
  99. sortPostProcessors(orderedPostProcessors, beanFactory);
  100. invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
  101. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
  102. for (String postProcessorName : nonOrderedPostProcessorNames) {
  103. nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
  104. }
  105. invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
  106. beanFactory.clearMetadataCache();
  107. }

我们可以具体分析一下 BeanFactoryPostProcessor 的子类 CustomEditorConfigurer 自定义属性编辑器来巩固一下执行流程

所谓属性编辑器是当你要自定义更改配置文件中的属性属性时,如 String 类型转为 Date 或者其他,下面的一个小例子展示如何 String 类型的属性怎么转化为 Address 属性

简单工程(Spring-version-5.3.18)

Person 类

  1. package cn.demo1;
  2. import lombok.Getter;
  3. import lombok.Setter;
  4. @Setter
  5. @Getter
  6. @ToString
  7. public class Person {
  8. private String name;
  9. private Address address;
  10. }

Address 类

  1. package cn.demo1;
  2. @Setter
  3. @Getter
  4. @ToString
  5. public class Address {
  6. private String city;
  7. private String town;
  8. }

AddressParse 类

  1. package cn.demo1;
  2. import java.beans.PropertyEditorSupport;
  3. public class AddressParse extends PropertyEditorSupport {
  4. @Override
  5. public void setAsText(String text) throws IllegalArgumentException {
  6. final String[] vals = text.split(",");
  7. Address addr = new Address();
  8. addr.setProvince(vals[0]);
  9. addr.setCity(vals[1]);
  10. setValue(addr);
  11. }
  12. }

MyCustomEditor 类

  1. package cn.demo1;
  2. import org.springframework.beans.PropertyEditorRegistrar;
  3. import org.springframework.beans.PropertyEditorRegistry;
  4. public class MyCustomEditor implements PropertyEditorRegistrar {
  5. @Override
  6. public void registerCustomEditors(PropertyEditorRegistry registry) {
  7. registry.registerCustomEditor(Address.class, new AddressParse());
  8. }
  9. }

配置文件 test1.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
  5. <!-- 待属性编辑的beanvalue代表的就是string类型-->
  6. <bean class="cn.demo1.Person" id="person">
  7. <property name="name" value="李华"/>
  8. <property name="address" value="四川,成都"/>
  9. </bean>
  10. <!-- 注册属性编辑器-->
  11. <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer" id="configurer">
  12. <property name="propertyEditorRegistrars">
  13. <list>
  14. <bean class="cn.demo1.MyCustomEditor"/>
  15. </list>
  16. </property>
  17. </bean>
  18. </beans>

测试类 EdT

  1. package cn.test1;
  2. import cn.demo1.Person;
  3. import org.junit.Test;
  4. import org.springframework.context.ApplicationContext;
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;
  6. public class EdT {
  7. @Test
  8. public void test1() {
  9. ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");
  10. final Person bean = context.getBean(Person.class);
  11. System.out.println(bean);
  12. }
  13. }
  14. =====================测试结果
  15. Person(name=李华, address=Address(province=四川, city=成都))

可以看见我们成功的将 String 类型转化为 Address 类型,让我们来看看实现流程,

  • 首先实现 PropertyEditorSupport 来自定义属性编辑规则
  • 其次将你的编辑规则给到 PropertyEditorRegistrar 子类里进行注册
  • 最后在 Spring 中配置 CustomEditorConfigurer 类然后注入你的 PropertyEditorRegistrar 注册器

让我们 debug 走一遍

如果你已经耐心看完上面的BeanFactoryPostProcessor执行时期的探究那么你应该可以知道接下来我们的步骤应该是进入 invokeBeanFactoryPostProcessors 这个方法里了

  1. private static void invokeBeanFactoryPostProcessors(
  2. Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
  3. for (BeanFactoryPostProcessor postProcessor : postProcessors) {
  4. StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
  5. .tag("postProcessor", postProcessor::toString);
  6. postProcessor.postProcessBeanFactory(beanFactory);
  7. postProcessBeanFactory.end();
  8. }
  9. }

很明显它执行 postProcessBeanFactory 这个方法

我们探究的 BFPP 正是 CustomEditorConfigurer,所以这个是 CustomEditorConfigurer 对 BFPP 的 postProcessBeanFactory 实现

  1. // 必然有个set方法让我们进行注入
  2. public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) {
  3. this.propertyEditorRegistrars = propertyEditorRegistrars;
  4. }
  5. @Override
  6. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  7. if (this.propertyEditorRegistrars != null) {
  8. for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
  9. // 把它加入Bean工厂里后面可以进行调用
  10. private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<>(4);
  11. beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
  12. }
  13. }
  14. if (this.customEditors != null) {
  15. this.customEditors.forEach(beanFactory::registerCustomEditor);
  16. }
  17. }

关于这个注册器使用要到后面填充属性的时候才会用到,

我其实觉得这个有点瑕疵,因为 BFPP 作用影响应该是当 Spring 还未创建 bean 的时候,可以用 BFPP 进行修改操作,可是这个属性编辑却影响了 bean 创建过后的修改操作,那么它就替代了 BPP(BeanPostProcessor)的作用发挥了。(以上仅仅代表个人的观点,有可能是我想错了)

当我们 debug 到 AbstractAutowireCapableBeanFactory 的 populateBean 这个方法填充 bean 的属性的时候,

让我们看看它的方法,其中我省略了大部分无关代码

  1. protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  2. // 这个是如果你配置的bean中有属性值的话
  3. // 也就是如下的配置,那么pvs不会为空的
  4. /**
  5. <bean class="cn.demo1.Person" id="person">
  6. <property name="name" value="李华"/>
  7. <property name="address" value="四川,成都"/>
  8. </bean>
  9. */
  10. PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
  11. if (pvs != null) {
  12. // 属性操作
  13. applyPropertyValues(beanName, mbd, bw, pvs);
  14. }
  15. }

让我们继续看看 applyPropertyValues 这个方法,无关的代码我也给省略了

  1. protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
  2. // PropertyValues接口的默认实现。允许对属性进行简单操作,并提供构造函数以支持从 Map 进行深度复制和构造。
  3. MutablePropertyValues mpvs = null;
  4. List<PropertyValue> original;
  5. // 可以进去
  6. if (pvs instanceof MutablePropertyValues) {
  7. mpvs = (MutablePropertyValues) pvs;
  8. // 默认为false,即我们需要类型转换
  9. if (mpvs.isConverted()) {
  10. // Shortcut: use the pre-converted values as-is.
  11. try {
  12. bw.setPropertyValues(mpvs);
  13. return;
  14. }
  15. catch (BeansException ex) {
  16. throw new BeanCreationException(
  17. mbd.getResourceDescription(), beanName, "Error setting property values", ex);
  18. }
  19. }
  20. // 把bean的属性以列表的形式展示出来
  21. original = mpvs.getPropertyValueList();
  22. }
  23. else {
  24. original = Arrays.asList(pvs.getPropertyValues());
  25. }
  26. // 默认为空
  27. TypeConverter converter = getCustomTypeConverter();
  28. if (converter == null) {
  29. converter = bw;
  30. }
  31. // 就一个组合类,帮助更好的bean的属性的解析
  32. BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
  33. // 深拷贝
  34. List<PropertyValue> deepCopy = new ArrayList<>(original.size());
  35. boolean resolveNecessary = false;
  36. for (PropertyValue pv : original) {
  37. if (pv.isConverted()) {
  38. deepCopy.add(pv);
  39. }
  40. else {
  41. // 获取bean的属性名字
  42. String propertyName = pv.getName();
  43. //获取bean属性值的包装对象
  44. Object originalValue = pv.getValue();
  45. // 自动装配的事情
  46. if (originalValue == AutowiredPropertyMarker.INSTANCE) {
  47. Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
  48. if (writeMethod == null) {
  49. throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
  50. }
  51. originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
  52. }
  53. // 把bean的属性值从包装类中分离出来
  54. Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
  55. Object convertedValue = resolvedValue;
  56. // 一般为true
  57. boolean convertible = bw.isWritableProperty(propertyName) &&
  58. !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
  59. if (convertible) {
  60. // 这个就是重点,对应我们的属性转化
  61. convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
  62. }
  63. }

继续追踪

  1. @Nullable
  2. private Object convertForProperty(
  3. @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
  4. // BeanWrapperImpl是继承TypeConverter的
  5. if (converter instanceof BeanWrapperImpl) {
  6. // 所以执行下面的方法
  7. return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
  8. }
  9. else {
  10. PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
  11. MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
  12. return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
  13. }
  14. }
  1. @Nullable
  2. public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
  3. CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
  4. PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
  5. if (pd == null) {
  6. throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
  7. "No property '" + propertyName + "' found");
  8. }
  9. TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
  10. if (td == null) {
  11. td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
  12. }
  13. // 上面的工作不用管,全是一些前戏工作,这个才是主题,至此我们的流程就到这里结束吧
  14. // 后面的流程太多了,大部分都是处理细节,你只需要知道大概的脉络就行,就是最终它肯定会
  15. // 走到AddressParse这个核心处理
  16. return convertForProperty(propertyName, null, value, td);
  17. }

你可以自己可以尝试 debug 一下,看别人实践真的不如自己动手实践一下,Spring 的包装类实属太多,但是可以抓住核心流程进行 debug。