Spring源码二十:Bean实例化流程三

上一篇Spring源码十九:Bean实例化流程二中,我们主要讨论了单例Bean创建对象的主要方法getSingleton了解到了他的核心流程无非是:通过一个简单工厂的getObject方法来实例化bean,当然spring在实例化前后提供了扩展如:beforeSingletonCreation与afterSingletonCreate,同样为了提供性能会将实例化后的单例bean放入缓存中;又因为spring设计之初存在三级缓存,所以在放入缓存的时候又会将其他两次的缓存清除。

简单的回忆了之前的内容,我们发现还有一个很重要的点我们没有说到那就是怎么通过简单工厂来创建实例对象的,这一篇咱们详细讨论一下:


createBean

	/*** Central method of this class: creates a bean instance, 创建bean实例对象* populates the bean instance, applies post-processors, etc. 填充bean实例、应用后置处理器* @see #doCreateBean*/@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolved at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.// 判断需要创建的bean是否可以实例化、是否可以通过当前类加载器加载Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.// 准备bean中的方法覆盖try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.// 给BeanPostProcessors一个返回代理而不是目标bean实例的机会。Object bean = resolveBeforeInstantiation(beanName, mbdToUse);// 如果bean配置类后置处理器PostProcessor,则这里返回一个proxy代理对象if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {// bean实例对象创建方法Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

因为lockup-method属性与repliace-methon配置属性,现在基本上没有使用场景,而resolveBeanClass与preprareMethodOverrides是为了是实现这个两个方法而生的,所以我们直接来看 resolveBeforeInstantiation方法。

resolveBeforeInstantiation

@Nullableprotected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {Object bean = null;if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {Class<?> targetType = determineTargetType(beanName, mbd);if (targetType != null) {// BeanPostProcessor前置处理方法bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);if (bean != null) {// BeanPostProcessor后置处理方法bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);}}}mbd.beforeInstantiationResolved = (bean != null);}return bean;}protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);if (result != null) {return result;}}}return null;}public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {Object current = processor.postProcessAfterInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;}

InstantiationAwareBeanPostProcessorBeanPostProcessor 的一个子接口,提供了以下方法,用于在 Bean 实例化的不同阶段进行干预:

  • postProcessBeforeInstantiation(Class<?> beanClass, String beanName): 在 Bean 实例化之前调用。
  • postProcessAfterInstantiation(Object bean, String beanName): 在 Bean 实例化之后调用。
  • postProcessProperties(PropertyValues pvs, Object bean, String beanName): 在 Bean 的属性设置之前调用。

这些方法提供了在 Bean 实例化过程中进行自定义逻辑处理的机会,可以用于 Bean 的替换、属性的预处理等操作。

示例代码:

public class CustomInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {if ("myBean".equals(beanName)) {System.out.println("Before instantiation of " + beanName);// 可以返回一个代理对象或自定义的 Bean 实例}return null; // 返回 null 表示继续默认的实例化过程}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) {System.out.println("After instantiation of " + beanName);return true; // 返回 true 表示继续进行属性设置}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {System.out.println("Processing properties for " + beanName);return pvs; // 可以修改属性值}
}

InstantiationAwareBeanPostProcessor 扩展了 BeanPostProcessor 的功能,提供了在 Bean 实例化的不同阶段进行干预的能力。通过实现 InstantiationAwareBeanPostProcessor 接口,开发人员可以在 Bean 实例化过程中插入自定义逻辑,实现更灵活的 Bean 管理和控制。

实例化与初始化

为了更好地理解 BeanPostProcessorInstantiationAwareBeanPostProcessor 的区别,我们需要明确实例化和初始化的概念。

  • 实例化:实例化是从零到一创建一个 Bean 的过程,即通过调用构造函数生成 Bean 的实例。
  • 初始化:初始化是在 Bean 实例化之后进行的配置过程,包括属性注入、调用初始化方法等。

在 Spring 容器中,Bean 的生命周期大致分为以下几个阶段:

  1. 实例化:通过调用构造函数创建 Bean 实例。
  2. 属性注入:将依赖的属性注入到 Bean 中。
  3. 初始化:调用自定义的初始化方法,进行额外的配置。

BeanPostProcessor 与 InstantiationAwareBeanPostProcessor 的区别

  • 作用阶段

    • BeanPostProcessor 主要作用于初始化阶段,即在 Bean 的属性已经注入之后进行处理。
    • InstantiationAwareBeanPostProcessor 作用于实例化阶段和属性注入阶段,允许在 Bean 实例化之前、之后以及属性注入之前进行处理。
  • 用途

    • BeanPostProcessor 常用于在 Bean 初始化之前和之后执行一些通用的处理逻辑,如代理增强、配置验证等。
    • InstantiationAwareBeanPostProcessor 常用于在 Bean 实例化过程中执行一些特殊的处理逻辑,如提前终止 Bean 创建、动态生成代理对象、修改属性注入逻辑等。

这个方法是在 Bean 初始化后应用所有注册的 BeanPostProcessorpostProcessAfterInitialization 方法,其设计和实现反映了 Spring 框架中依赖注入和面向切面编程的核心理念。

Spring Bean 生命周期管理

在 Spring 框架中,Bean 的生命周期经历了多个阶段,包括实例化、依赖注入、初始化和销毁等。applyBeanPostProcessorsAfterInitialization 方法所处的阶段是在 Bean 初始化之后,即在所有属性被设置后,执行自定义的后处理逻辑。

BeanPostProcessor 接口作用

BeanPostProcessor 接口定义了在 Bean 初始化前后可以插入自定义逻辑的能力。Spring 容器在创建 Bean 的过程中,会检查是否注册了 BeanPostProcessor,如果有,则会在相应的阶段调用其方法。其中,postProcessAfterInitialization 方法是在 Bean 初始化完成后被调用的,允许开发者对 Bean 进行额外的处理或修改。

applyBeanPostProcessorsAfterInitialization 方法分析

  1. 初始化结果对象:方法开始时,首先将 result 对象初始化为 existingBean,即当前的 Bean 实例。这个 existingBean 是在容器中已经完成初始化的对象。

  2. 遍历处理器列表:方法接着遍历所有注册的 BeanPostProcessor,对每一个后处理器调用其 postProcessAfterInitialization 方法。

    • 每个处理器可以在方法内部执行任何与 Bean 相关的操作,例如添加代理、执行验证、修改属性等。
    • 如果某个处理器返回 null,则表示不需要进一步处理,直接返回当前的 result 对象。
  3. 返回处理后的结果:最终返回经过所有后处理器处理后的 result 对象。这个对象可能是原始的 existingBean,也可能是经过多个处理器处理后的新对象。

技术原理分析

  • 面向切面编程(AOP)的应用:通过 BeanPostProcessor 接口,Spring 实现了 AOP 的一种简单形式。开发者可以在 Bean 初始化后插入切面逻辑,例如添加事务、日志等。

  • 依赖注入的增强:允许在 Bean 初始化后对依赖关系进行增强或修改,以适应不同的运行时需求。

  • 灵活性与可扩展性:applyBeanPostProcessorsAfterInitialization 方法展示了 Spring 框架在管理 Bean 生命周期时的高度灵活性和可扩展性。开发者可以通过注册自定义的 BeanPostProcessor 实现特定的业务逻辑,而不必修改现有的 Bean 实现代码。

applyBeanPostProcessorsAfterInitialization 方法在 Spring 框架中扮演了重要角色,通过它,开发者可以在 Bean 初始化完成后添加自定义逻辑,扩展和定制应用程序的行为。理解这个方法的工作原理和技术实现,有助于深入理解 Spring 容器的工作机制,提升对 Bean 生命周期管理的控制和应用开发的灵活性。

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/43938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第5章-组合序列类型

#全部是重点知识&#xff0c;必须会。 了解序列和索引|的相关概念 掌握序列的相关操作 掌握列表的相关操作 掌握元组的相关操作 掌握字典的相关操作 掌握集合的相关操作1&#xff0c;序列和索引 1&#xff0c;序列是一个用于存储多个值的连续空间&#xff0c;每一个值都对应一…

灵活多变的对象创建——工厂方法模式(Python实现)

1. 引言 大家好&#xff0c;又见面了&#xff01;在上一篇文章中&#xff0c;我们聊了聊简单工厂模式&#xff0c;今天&#xff0c;我们要进一步探讨一种更加灵活的工厂设计模式——工厂方法模式。如果说简单工厂模式是“万能钥匙”&#xff0c;那工厂方法模式就是“变形金刚”…

Python采集京东标题,店铺,销量,价格,SKU,评论,图片

京东的许多数据是通过 JavaScript 动态加载的&#xff0c;包括销量、价格、评论和评论时间等信息。我们无法仅通过传统的静态网页爬取方法获取到这些数据。需要使用到如 Selenium 或 Pyppeteer 等能够模拟浏览器行为的工具。 另外&#xff0c;京东的评论系统是独立的一个系统&a…

offer题目33:判断是否是二叉搜索树的后序遍历序列

题目描述&#xff1a;输入一个整数数组&#xff0c;判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。例如&#xff0c;输入数组{5,7,6,9,11,10,8},则返回true,&#xff0c;因为这个整数是下图二叉搜索树…

c++内存管理(上)

目录 引入 分析 说明 C语言中动态内存管理方式 C内存管理方式 new/delete操作内置类型 new和delete操作自定义类型 引入 我们先来看下面的一段代码和相关问题 int globalVar 1; static int staticGlobalVar 1; void Test() { static int staticVar 1; int localVar 1…

数图助推朝阳佳惠辽宁华联开启数字化导航、精细化管理新纪元!

近期&#xff0c;辽宁省著名零售企业朝阳佳惠与辽宁华联&#xff0c;秉持创新精神&#xff0c;大胆尝试&#xff0c;在品类空间管理方面推出了创新举措。引入了先进的数图可视化陈列管理系统&#xff0c;通过智能化、直观化的方式优化商品布局。此举不仅大幅提高了商品管理的效…

element-ui封装分页组件:实现首页、上一页、下一页、末页、跳转按钮

首页、上一页、下一页、末页、跳转按钮 因为el-pagination只有一个插槽&#xff0c;所以通过两个el-pagination插槽分别加入首页、末页按钮&#xff0c;再拼接这两个el-pagination的方式来实现首页、末页按钮跳转按钮不用加事件&#xff0c;如果el-pagination修改了前往的页数…

【work】AI八股-神经网络相关

Deep-Learning-Interview-Book/docs/深度学习.md at master amusi/Deep-Learning-Interview-Book GitHub 网上相关总结&#xff1a; 小菜鸡写一写基础深度学习的问题&#xff08;复制大佬的&#xff0c;自己复习用&#xff09; - 知乎 (zhihu.com) CV面试问题准备持续更新贴 …

聚类分析方法(二)

目录 三、层次聚类方法&#xff08;一&#xff09;层次聚类策略&#xff08;二&#xff09;AGNES算法&#xff08;三&#xff09;DIANA算法 四、密度聚类方法&#xff08;一&#xff09;基本概念&#xff08;二&#xff09;算法描述&#xff08;三&#xff09;计算实例&#xf…

Google账号输入用户名和密码后提醒要到手机通知点是,还要点击数字,但是我手机收不到

有一些朋友换了一个新的电脑后手机登录谷歌账号时&#xff0c;用户名和密码都正确输入以后&#xff0c;第三步弹出一个提示&#xff0c;要在手机上的通知栏点击是&#xff0c;并且点击手机上相应的数字才能继续登录。 但是自己的手机上下拉通知栏却没有来自谷歌的通知&#xf…

符号同步、定时同步和载波同步

符号同步、定时同步和载波同步是通信系统中重要的同步技术&#xff0c;它们各自承担着不同的功能和作用。以下是对这三种同步技术的详细解释&#xff1a; 符号同步 定义&#xff1a; 符号同步&#xff0c;也称为定时恢复或时钟恢复&#xff0c;是指在数字通信系统中&#xff…

继承关系中的访问控制

继承关系中的访问控制 类中成员的访问权限类继承中的访问权限派生类向基类转换的权限问题&#xff08;向上转型&#xff09;友元在继承中的访问权限 类中成员的访问权限 public&#xff1a;类的对象&#xff08;外部&#xff09;可以访问&#xff0c;派生类也可以访问protecte…

LeNet原理及代码实现

目录 1.原理及介绍 2.代码实现 2.1model.py 2.2model_train.py 2.3model.test.py 1.原理及介绍 2.代码实现 2.1model.py import torch from torch import nn from torchsummary import summaryclass LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__…

nuxt、vue树形图d3.js

直接上代码 //安装 npm i d3 --save<template><div class"d3"><div :id"id" class"d3-content"></div></div> </template> <script> import * as d3 from "d3";export default {props: {d…

Github Actions 构建Vue3 + Vite项目

本篇文章以自己创建的项目为例&#xff0c;用Github Actions构建。 Github地址&#xff1a;https://github.com/ling08140814/myCarousel 访问地址&#xff1a;https://ling08140814.github.io/myCarousel/ 具体步骤&#xff1a; 1、创建一个Vue3的项目&#xff0c;并完成代…

接口基础知识1:认识接口

课程大纲 一、定义 接口&#xff1a;外部与系统之间、内部各子系统之间的交互点。 比如日常使用的电脑&#xff0c;有电源接口、usb接口、耳机接口、显示器接口等&#xff0c;分别可以实现&#xff1a;与外部的充电、文件数据传输、声音输入输出、图像输入输出等功能。 接口的本…

262个地级市-市场潜力指数(do文件+原始文件)

全国262个地级市-市场潜力指数&#xff08;市场潜力计算方法代码数据&#xff09;_市场潜力数据分析资源-CSDN文库 市场潜力指数&#xff1a;洞察未来发展的指南针 市场潜力指数是一个综合性的评估工具&#xff0c;它通过深入分析市场需求、竞争环境、政策支持和技术创新等多个…

(2)滑动窗口算法练习:无重复字符的最长子串

无重复字符的最长子串 题目链接&#xff1a;3. 无重复字符的最长子串 - 力扣&#xff08;LeetCode&#xff09; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长子串的长度。 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"a…

mov视频怎么改成mp4?把mov改成MP4的四个方法

mov视频怎么改成mp4&#xff1f;选择合适的视频格式对于确保内容质量和流通性至关重要。尽管苹果公司的mov格式因其出色的视频表现备受赞誉&#xff0c;但在某些情况下&#xff0c;它并非最佳选择&#xff0c;因为使用mov格式可能面临一些挑战。MP4格式在各种设备&#xff08;如…

构造二进制字符串

目录 LeetCode3221 生成不含相邻零的二进制字符串 #include <iostream> #include <vector> using namespace std;void dfs(string s,int n,vector<string>& res){if(s.size()n){res.push_back(s);return;}dfs(s"0",n,res);dfs(s"1"…