Spring 源码学习(六)扩展功能 上篇(下)

简介: 结束了前面的基础结构分析,了解到 Spring 是如何识别配置文件和进行解析属性,最终将 bean 加载到内存中。同时为了更好得理解 Spring 的扩展功能,我们先来巩固一下 beanFactory 和 bean 的概念,然后再分析新内容后处理器 PostProcessor 。

流程图

11.jpg

代码

  1. public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
  2.    Set<String> processedBeans = new HashSet<>();
  3.    // beanFactory 默认使用的是 DefaultListableBeanFactory,属于 BeanDefinitionRegistry
  4.    if (beanFactory instanceof BeanDefinitionRegistry) {
  5.        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
  6.        // 两个后处理器列表
  7.        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
  8.        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
  9.        // 硬编码注册的后处理器
  10.        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
  11.            // 分类处理
  12.        }
  13.        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
  14.        // 首先,调用实现 priorityOrder 的 beanDefinition 这就是前面提到过的优先级概念,这一步跟下面的优先级不一样之处,这一步的优先级是带有权重
  15.        String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  16.        for (String ppName : postProcessorNames) {
  17.            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
  18.                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  19.                processedBeans.add(ppName);
  20.            }
  21.        }
  22.        // 对后处理器进行排序
  23.        sortPostProcessors(currentRegistryProcessors, beanFactory);
  24.        registryProcessors.addAll(currentRegistryProcessors);
  25.        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  26.        currentRegistryProcessors.clear();
  27.        // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
  28.        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  29.        for (String ppName : postProcessorNames) {
  30.            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
  31.                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  32.                processedBeans.add(ppName);
  33.            }
  34.        }
  35.        sortPostProcessors(currentRegistryProcessors, beanFactory);
  36.        registryProcessors.addAll(currentRegistryProcessors);
  37.        // 执行 definitionRegistryPostProcessor 接口的方法 :postProcessBeanDefinitionRegistry
  38.        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  39.        currentRegistryProcessors.clear();
  40.        // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.最后,调用所有其他后处理器,直到不再出现其他 bean 为止
  41.        boolean reiterate = true;
  42.        while (reiterate) {
  43.            reiterate = false;
  44.            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  45.            for (String ppName : postProcessorNames) {
  46.                if (!processedBeans.contains(ppName)) {
  47.                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  48.                    processedBeans.add(ppName);
  49.                    reiterate = true;
  50.                }
  51.            }
  52.            sortPostProcessors(currentRegistryProcessors, beanFactory);
  53.            registryProcessors.addAll(currentRegistryProcessors);
  54.            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  55.            currentRegistryProcessors.clear();
  56.        }
  57.        // 执行 postProcessBeanFactory 回调方法
  58.        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
  59.        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
  60.    }
  61.    else {
  62.        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
  63.    }
  64.    // 不要在这里初始化 factoryBean:我们需要保留所有常规 bean 未初始化,以便让 bean 工厂后处理程序应用于它们
  65.    // 注释 6.4 在这个步骤中,我们自定义的 carBeanFactoryPostProcessor 才真正注册并执行
  66.    String[] postProcessorNames =
  67.            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);.
  68.    // 跳过分类的逻辑
  69.    // 首先执行的是带有权重顺序的后处理器
  70.    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
  71.    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
  72.    // 下一步执行普通顺序的后处理器
  73.    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
  74.    for (String postProcessorName : orderedPostProcessorNames) {
  75.        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
  76.    }
  77.    sortPostProcessors(orderedPostProcessors, beanFactory);
  78.    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
  79.    // 最后执行的是普通的后处理器
  80.    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
  81.    for (String postProcessorName : nonOrderedPostProcessorNames) {
  82.        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
  83.    }
  84.    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
  85.    // 清除缓存的合并bean定义,因为后处理程序可能已经修改了原始元数据,例如替换值中的占位符
  86.    beanFactory.clearMetadataCache();
  87. }

从上面贴的代码中能够看到,对于 beanFactoryPostProcessor 的处理主要分两种情况:

  • beanFactoryBeanDefinitionRegistry 类型:需要特殊处理
  • beanFactory 不是 BeanDefinitionRegistry 类型:进行普通处理

对于每种情况都需要考虑硬编码注入注册的后处理器(上面已经提到如何进行硬编码)以及通过配置注入的后处理器

对于 BeanDefinitionRegistry 类型的处理器的处理主要包括以下内容:

  1. 处理硬编码注册的后处理器
  2. 记录后处理器主要使用以下三个 List
  • registryPostProcessors:记录通过硬编码方式注册的 BeanDefinitionRegistryPostProcessor
  • regularPostProcessors:记录通过硬编码方式注册的 BeanFactoryPostProcessor
  • regitstryPostProcessorBeans:记录通过配置方式注册的 BeanDefinitionRegistryPostProcessor
  1. 对于以上后处理器列表,统一调用 BeanFactoryPostProcessorpostProcessBeanFactory 方法
  2. beanFactoryPostProcessors 中非 BeanDefinitionRegistryPostProcessor 类型的后处理器进行统一的 postProcessBeanFactory 方法
  3. 普通 beanFactory 处理:其实在这一步中,就是忽略了 BeanDefinitionRegistryPostProcessor 类型,对BeanFactoryPostProcessor 进行直接处理。

流程图中描述了整体调用链路,具体调用方法在代码中的注释也描述出来了,所以结合起来看应该能够理解整体流程~


总结

本次分析了 beanFactory 的后处理器 BeanFactoryPostProcessor,了解了 Spring 给我们提供的这个扩展接口使用用途和在源码中如何进行激活执行。


由于个人技术有限,如果有理解不到位或者错误的地方,请留下评论,我会根据朋友们的建议进行修正

代码和注释都在里面,小伙伴们可以下载我上传的代码,亲测可运行~

Gitee 地址:https://gitee.com/vip-augus/spring-analysis-note.git

Github 地址:https://github.com/Vip-Augus/spring-analysis-note


参考资料

  1. Bean 定义
  2. Sping 的 BeanFactory 容器
  3. Spring拓展接口之BeanFactoryPostProcessor,占位符与敏感信息解密原理
相关文章
|
19天前
|
XML 安全 Java
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
1月前
|
Java 开发者 微服务
手写模拟Spring Boot自动配置功能
【11月更文挑战第19天】随着微服务架构的兴起,Spring Boot作为一种快速开发框架,因其简化了Spring应用的初始搭建和开发过程,受到了广大开发者的青睐。自动配置作为Spring Boot的核心特性之一,大大减少了手动配置的工作量,提高了开发效率。
50 0
|
19天前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
43 14
|
17天前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
38 2
|
1月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
63 9
|
1月前
|
消息中间件 缓存 Java
手写模拟Spring Boot启动过程功能
【11月更文挑战第19天】Spring Boot自推出以来,因其简化了Spring应用的初始搭建和开发过程,迅速成为Java企业级应用开发的首选框架之一。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,帮助读者深入理解其工作机制。
42 3
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
80 2
|
29天前
|
Java Kotlin 索引
学习Spring框架特性及jiar包下载
Spring 5作为最新版本,更新了JDK基线至8,修订了核心框架,增强了反射和接口功能,支持响应式编程及Kotlin语言,引入了函数式Web框架,并提升了测试功能。Spring框架可在其官网下载,包括文档、jar包和XML Schema文档,适用于Java SE和Java EE项目。
32 0
|
7月前
|
Java 关系型数据库 数据库连接
Spring源码解析--深入Spring事务原理
本文将带领大家领略Spring事务的风采,Spring事务是我们在日常开发中经常会遇到的,也是各种大小面试中的高频题,希望通过本文,能让大家对Spring事务有个深入的了解,无论开发还是面试,都不会让Spring事务成为拦路虎。
104 1
下一篇
DataWorks