Spring 源码学习 12:registerBeanPostProcessors

简介: 前面通过 invokeBeanFactoryPostProcessors 这一步了解到了什么是 BeanFactoryPostProcessor ,以及 BeanFactoryPostProcessor 的使用及作用,并通过 invokeBeanFactoryPostProcessors 这一步源码,对 BeanFactoryPostProcessor 的加载流程有了进一步了解。

前言


前面通过 invokeBeanFactoryPostProcessors 这一步了解到了什么是 BeanFactoryPostProcessor ,以及 BeanFactoryPostProcessor 的使用及作用,并通过 invokeBeanFactoryPostProcessors 这一步源码,对 BeanFactoryPostProcessor 的加载流程有了进一步了解。


现在就一起进入下一个环节:

registerBeanPostProcessors(beanFactory);

这一步主要的作用是加载 BeanPostProcessor,从名字也可以看出,只是加载,并没有执行。

不过,在进入源码之前,依然是结合官网,先了解以下几个问题:

  1. 什么是 BeanPostProcessor?
  2. BeanPostProcessor 是如何使用的?
  3. BeanPostProcessor 有什么用?


什么是 BeanPostProcessor ?

网络异常,图片无法展示
|

如截图所示,在官网 1.8.1 Customizing Beans by Using a BeanPostProcessor 中介绍, BeanPostProcessor 接口定义回调方法,可以实现这些方法,从而在 Bean 实例化期间修改 Bean 的属性。


BeanPostProcessor 是如何使用的?

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
  @Override
  public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof UserComponent) {
      System.out.println("BeanPostProcessor 开始执行 初始化前..." + beanName);
      UserComponent userComponent = (UserComponent) bean;
      userComponent.setUserName("liuzhihang-postProcessBeforeInitialization");
      return userComponent;
    }
    return bean;
  }
  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof UserComponent) {
      System.out.println("BeanPostProcessor 开始执行 初始化后..." + beanName);
      UserComponent userComponent = (UserComponent) bean;
      userComponent.setUserName("liuzhihang-postProcessAfterInitialization");
      return userComponent;
    }
    return bean;
  }
}

如代码所示,只需要声明一个自己的 MyBeanPostProcessor 来实现 BeanPostProcessor 并重写其方法:

postProcessBeforeInitialization :在 Bean 实例后调用初始化方法之前进行处理。

postProcessAfterInitialization :在 Bean 实例化后调用初始化方法之后进行处理。

并且在测试时可以发现,BeanPostProcessor 修改的属性会覆盖


BeanFactoryPostProcessor,至于原因可以阅读下 Spring 源码学习 11:invokeBeanFactoryPostProcessors 这篇文章,相信对 BeanFactoryPostProcessor 有了一定的了解之后,一定会有自己的答案。


当然我个人的理解就是 BeanFactoryPostProcessor 是在 Bean 实例化之前,是通过修改元数据从而修改的 Bean 的元素信息。

这块也可以通过代码进行验证。

网络异常,图片无法展示
|


可以看出,执行顺序是

BeanFactoryPostProcessor#postProcessBeanFactory->BeanPostProcessor#postProcessBeforeInitialization->BeanPostProcessor#postProcessAfterInitialization

所以,后面修改的属性,会覆盖之前修改的属性。

至于 BeanPostProcessor 是如何修改属性的,在这里先不做介绍,继续进入本节的主角 registerBeanPostProcessors 源码分析


registerBeanPostProcessors 源码

在 Spring refresh 方法中,执行 registerBeanPostProcessors 主要作用是将 BeanPostProcessor 注册到容器中,源码如下:

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

这里调用了 PostProcessorRegistrationDelegate 类的静态方法,继续跟进:

public static void registerBeanPostProcessors(
        ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    // 查找 BeanPostProcessor 类型的 Bean 的名称集合, 就是获取所有继承了 BeanPostProcessor 的类
    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    // Register BeanPostProcessorChecker that logs an info message when
    // a bean is created during BeanPostProcessor instantiation, i.e. when
    // a bean is not eligible for getting processed by all BeanPostProcessors.
    //  注册一个 BeanPostProcessorChecker,用来记录 bean 在 BeanPostProcessor 实例化时的信息。
    int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    // Separate between BeanPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    // 四个集合 区分实现不同接口的 BeanPostProcessors
    List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
            priorityOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
        } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        } else {
            nonOrderedPostProcessorNames.add(ppName);
        }
    }
    // First, register the BeanPostProcessors that implement PriorityOrdered.
    // 排序后执行 实现 PriorityOrdered 的 BeanPostProcessors
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
    // Next, register the BeanPostProcessors that implement Ordered.
    List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
    for (String ppName : orderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        orderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, orderedPostProcessors);
    // Now, register all regular BeanPostProcessors.
    List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String ppName : nonOrderedPostProcessorNames) {
        BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
        nonOrderedPostProcessors.add(pp);
        if (pp instanceof MergedBeanDefinitionPostProcessor) {
            internalPostProcessors.add(pp);
        }
    }
    registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    // Finally, re-register all internal BeanPostProcessors.
    sortPostProcessors(internalPostProcessors, beanFactory);
    registerBeanPostProcessors(beanFactory, internalPostProcessors);
    // Re-register post-processor for detecting inner beans as ApplicationListeners,
    // moving it to the end of the processor chain (for picking up proxies etc).
    beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}

代码中添加了相应的注释,相信读过上一篇文章(invokeBeanFactoryPostProcessors 源码)的小伙伴,一定会感觉非常熟悉,这个方法的逻辑和上面基本一致,都是声明集合,排序,注册到 BeanFactory 中。

不过还是有区别的:

registerBeanPostProcessors 这一步仅仅将 BeanPostProcessor 注册到 BeanFactory 中,并没有执行!!!


总结


本文源码部分相对比较简单,主要花费部分篇幅介绍什么是 BeanPostProcessor 以及 BeanPostProcessor 的使用方法。

一句话总结这一步就是:注册 BeanPostProcessor 到 BeanFactory 中,但是没有执行。

网络异常,图片无法展示
|


目录
相关文章
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的公考学习平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的公考学习平台附带文章源码部署视频讲解等
34 5
|
1月前
|
Java 数据格式 微服务
2024最新首发,全网最全 Spring Boot 学习宝典(附思维导图)
📚 《滚雪球学Spring Boot》是由CSDN博主bug菌创作的全面Spring Boot教程。作者是全栈开发专家,在多个技术社区如CSDN、掘金、InfoQ、51CTO等担任博客专家,并拥有超过20万的全网粉丝。该教程分为入门篇和进阶篇,每篇包含详细的教学步骤,涵盖Spring Boot的基础和高级主题。
110 4
2024最新首发,全网最全 Spring Boot 学习宝典(附思维导图)
|
1月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的在线学习过程管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的在线学习过程管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的在线学习过程管理系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
22天前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
60 11
|
20天前
|
安全 Java 数据库
三更草堂 Spring Security学习总结(思路整理)
Spring Security学习总结(思路整理)
|
23天前
|
缓存 Java 程序员
spring IoC 源码
spring IoC 源码
38 3
|
1月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的大学生国学自主学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的大学生国学自主学习平台的详细设计和实现(源码+lw+部署文档+讲解等)
|
1月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的诗词学习系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的诗词学习系统的详细设计和实现(源码+lw+部署文档+讲解等)
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的学生网课学习效果评价附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的学生网课学习效果评价附带文章源码部署视频讲解等
51 2
|
1月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的语言课学习系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的语言课学习系统附带文章源码部署视频讲解等
27 3