SpringBoot原理解析(二)- Spring Bean的生命周期以及后处理器和回调接口

SpringBoot原理解析(二)- Spring Bean的生命周期以及后处理器和回调接口

文章目录

  • SpringBoot原理解析(二)- Spring Bean的生命周期以及后处理器和回调接口
    • 1.Bean的实例化阶段
      • 1.1.Bean 实例化的基本流程
      • 1.2.Bean 实例化图例
      • 1.3.实例化阶段的后处理器
        • 1.3.1.实例化阶段后处理器的介入流程图
        • 1.3.2.BeanDefinitionRegistryPostProcessor
        • 1.3.3.BeanFactoryPostProcessor
    • 2.Bean的初始化阶段
      • 2.1.主要流程
      • 2.2.初始化流程图
      • 2.3.循环依赖
        • 2.3.1.问题描述
        • 2.3.2.三级缓存
        • 2.3.3.三级缓存流程图
    • 3.Bean的完成阶段
    • 4.Bean的销毁阶段

Spring Bean的生命周期指从Bean的创建(实例化)、初始化,到使用(完成)和销毁的整个过程。

  • Bean的实例化阶段:Spring会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的, 是否不是延迟加载的,是否不是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;

  • Bean的初始化阶段:Bean创建之后还仅仅是个"半成品",还需要对Bean实例的属性进行填充、执行一些Aware 接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法 等。该阶段是Spring最具技术含量和复杂度的阶段,Aop增强功能,相关注解功能等、 Bean的循环引用问题都是在这个阶段体现的;

  • Bean的完成阶段:经过初始化阶段,Bean就成为了一个完整的Spring Bean,被存储到单例池 singletonObjects中去了。

  • Bean的销毁阶段:当Bean不再使用时,Spring会调用Bean的销毁方法进行清理工作。

1.Bean的实例化阶段

1.1.Bean 实例化的基本流程

Spring容器在进行初始化时,会将xml配置的的信息封装成一个BeanDefinition对象(详细请见《SpringBoot原理解析(一)- 基于xml配置bean(Java解析xml文件)》),所有的 BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去,Spring框架在对该Map进行遍历,使用反射创建Bean实例对象,创建好的Bean对象存储在一个名为singletonObjects的Map集合中,当调用getBean方法 时则最终从该Map集合中取出Bean实例对象返回。

步骤:

  • 加载xml配置文件,解析获取配置中的每个的信息,封装成一个个的BeanDefinition对象;

  • 将BeanDefinition存储在一个名为beanDefinitionMap的Map中;

  • ApplicationContext底层遍历beanDefinitionMap,创建Bean实例对象;

  • 创建好的Bean实例对象,被存储到一个名为singletonObjects的Map中;

  • 当执行applicationContext.getBean(beanName)时,从singletonObjects去匹配Bean实例返回

1.2.Bean 实例化图例

在这里插入图片描述

1.3.实例化阶段的后处理器

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册 BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。

  • BeanFactoryPostProcessor:Bean工厂后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行;

  • BeanDefinitionRegistryPostProcessor:BeanDefinition注册后处理器,在BeanDefinitionMap填充完毕,Bean实例化之前执行singletonObjects之前执行。

1.3.1.实例化阶段后处理器的介入流程图

在这里插入图片描述

1.3.2.BeanDefinitionRegistryPostProcessor

在Spring容器初始化过程中,首先会加载Bean定义,然后通过注册机制将这些Bean定义注册到容器中。在Bean定义注册的过程中,如果我们需要对Bean定义进行修改或添加一些自定义的处理逻辑,可以实现BeanDefinitionRegistryPostProcessor接口,并实现其中的postProcessBeanDefinitionRegistry 方法。

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {/*** 在所有的Bean定义加载完毕后,但在Bean的实例化和初始化之前执行* 注意:该处理器方法优先于postProcessBeanFactory*/void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;}
1.3.3.BeanFactoryPostProcessor

在Spring容器初始化过程中,当所有的Bean定义加载完成后,但在Bean的实例化和初始化之前,会调用所有实现了BeanFactoryPostProcessor接口的类的postProcessBeanFactory方法。

public interface BeanFactoryPostProcessor {/*** 在所有的Bean定义加载完毕后,但在Bean的实例化和初始化之前执行*/void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}

2.Bean的初始化阶段

2.1.主要流程

Spring Bean的初始化过程涉及如下几个过程,执行优先级从上到下:

  1. org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

  2. Bean的构造器方法

  3. org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

  4. org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessProperties

  5. Bean属性填充

    Bean实例属性填充 Spring在进行属性注入时,会分为如下几种情况:

    • 注入普通属性,String、Integer或存储基本类型的集合时,直接通过set方法的反射设置进去;

    • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射设置进去,如果容器中没有,则先创建被 注入对象Bean实例(完成整个生命周期)后,在进行注入操作;

    • 注入双向对象引用属性时,就比较复杂了,涉及了循环引用(循环依赖)问题。

  6. org.springframework.beans.factory.BeanNameAware#setBeanName

  7. org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader

  8. org.springframework.beans.factory.BeanFactoryAware#setBeanFactory

  9. org.springframework.context.ApplicationContextAware#setApplicationContext

  10. org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization

  11. @postConstruct

  12. org.springframework.beans.factory.InitializingBean#afterPropertiesSet

  13. @Bean注解解析的初始化方法initMethod()

  14. org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization

2.2.初始化流程图

在这里插入图片描述

2.3.循环依赖

2.3.1.问题描述
<!-- userService依赖了orderService -->
<bean id="userService" class="org.ahao.demo.service.UserService"><property name="orderService" re="orderService"/>
</bean><!-- orderService依赖了userService -->
<bean id="orderService" class="org.ahao.demo.service.OrderService"><property name="userService" re="userService"/>
</bean>
2.3.2.三级缓存

通过使用三级缓存,Spring可以提高Bean实例的获取效率和避免循环引用带来的问题。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {/** Cache of singleton objects: bean name to bean instance. */// ”第一级缓存“:实例化和初始化都完成了的完整Beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of early singleton objects: bean name to bean instance. */// ”第二级缓存“:半成品Bean,并且该Bean已经被其他的Bean对象引用了private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);/** Cache of singleton factories: bean name to ObjectFactory. */// “第三级缓存”:半成品Bean,该Bean未被其他的Bean对象引用private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);}

大致流程如下:

  • UserService 实例化对象,但尚未初始化,将UserService存储到第三级缓存singletonFactories;
  • UserService 属性注入,需要OrderService,从缓存中获取,没有OrderService;
  • OrderService实例化对象,但尚未初始化,将OrderService存储到到第三级缓存singletonFactories;
  • OrderService属性注入,需要UserService,从三级缓存获取UserService,UserService从第三级缓存singletonFactories移入第二级缓存earlySingletonObjects;
  • OrderService执行其他生命周期过程,最终成为一个完成Bean,存储到第一级缓存singletonObjects,删除第二三级缓存;
  • UserService 注入OrderService;
  • UserService执行其他生命周期过程,最终成为一个完成Bean,存储到第一级缓存singletonObjects,删除二三级缓存。
2.3.3.三级缓存流程图

在这里插入图片描述

3.Bean的完成阶段

在初始化后,Bean可以被容器和其他Bean使用。此时,Bean处于活动状态,并可以响应外部请求。

@Service
public class OrderServiceImpl implement OrderService {@Autowired// 注入beanprivate UserService userService;@Overridepublic User getOrderUser(long orderId){// 根据订单id获取uidString uid = ...// 使用Bean(已完成初始化,成为一个完整的Bean)return userService.getUserById(uid);}}

4.Bean的销毁阶段

当Bean不再使用时,Spring会调用Bean的销毁方法进行清理工作。可以通过实现DisposableBean接口并实现destroy方法,或使用@PreDestroy注解定义销毁方法。

  • @PreDestroy
  • org.springframework.beans.factory.DisposableBean#destroy

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

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

相关文章

go 协程池的实现

使用场景 这次需求是做一个临时的数据采集功能&#xff0c;为了将积压的数据快速的消耗完&#xff0c;但是单一的脚本消耗的太慢&#xff0c;于是乎就手写了一个简单的协程池&#xff1a; 为了能加快数据的收集速度为了稳定协程的数量&#xff0c;让脚本变得稳定 设计图如下…

数据增强:机器学习中的数据魔法

数据增强&#xff1a;机器学习中的数据魔法 在机器学习领域&#xff0c;数据是模型训练的基石。然而&#xff0c;获取大量高质量的训练数据往往是一个挑战。数据增强技术应运而生&#xff0c;它通过从现有数据中生成新的变体来增加数据集的多样性和丰富性。本文将深入探讨数据…

微服务分布式事务

1、分布式事务是什么&#xff1f; 微服务架构中的分布式事务是指在多个服务实例之间保持数据一致性的机制。由于微服务通常涉及将业务逻辑拆分成独立的服务&#xff0c;每个服务可能有自己的数据库&#xff0c;因此当一个业务操作需要跨多个服务进行时&#xff0c;确保所有服务…

sbti科学碳目标倡议是什么

在科学界、工业界以及全球政策制定者的共同努力下&#xff0c;一个名为“科学碳目标倡议”&#xff08;Science Based Targets initiative&#xff0c;简称SBTi&#xff09;的全球性合作平台应运而生。这一倡议旨在推动企业和组织设定符合气候科学要求的减排目标&#xff0c;以…

2023年国际高校数学建模竞赛

2023年国际高校数学建模竞赛是一项由国际(澳门)学术研究院数学科学研究所、数学建模研究与应用期刊社联合香港数学研究与应用学会主办的国际性学科竞赛&#xff0c;该竞赛已获澳门特别行政区政府澳门基金会&#xff08;行政长官直属&#xff09;立项资助。以下是对该竞赛的详细…

生成式AI未来发展方向充满了无限可能与挑战

生成式AI&#xff0c;作为人工智能领域的一个前沿分支&#xff0c;其未来发展方向充满了无限可能与挑战&#xff0c;将对多个行业产生深远影响。以下是我对生成式AI未来发展方向的几点看法&#xff1a; 技术融合与创新 未来&#xff0c;生成式AI将更加注重与其他技术的深度融合…

问题记录-SpringBoot 2.7.2 整合 Swagger 报错

详细报错如下 报错背景&#xff0c;我将springboot从2.3.3升级到了2.7.2&#xff0c;报了下面的错误&#xff1a; org.springframework.context.ApplicationContextException: Failed to start bean documentationPluginsBootstrapper; nested exception is java.lang.NullPo…

信息收集Part3-资产监控

Github监控 便于收集整理最新exp或poc 便于发现相关测试目标的资产 各种子域名查询 DNS,备案&#xff0c;证书 全球节点请求cdn 枚举爆破或解析子域名对应 便于发现管理员相关的注册信息 通过Server酱接口接收漏洞信息 https://sct.ftqq.com/ https://github.com/easych…

从苏宁电器到卡巴斯基(第二部)第36篇:我当高校教师的这几年 XII

你们是八九点钟的太阳 想想也是有趣,自从我2018年3月入职X高校之后,一直到2019年9月,在这3个学期的时间里面,我讲课的对象全都是大三的同学,而且都是属于专业方向课,比如网络安全、物联网这种。第一学期尽管也教过C++,但是他们毕竟已经是大三第二学期,从心态上来说,他…

2024.7.23(DNS正向解析)

回顾&#xff1a; # 安装 samba yum -y install samba # 自建库&#xff0c;只下载&#xff0c;不安装 yum -y install --downloadonly --downloaddir./soft/ # 配置samba vim /etc/samba/smb.conf # 配置 [xxxxxxxname] commentdasdffsffdslfdjsa path/share …

h5点击电话号跳转手机拨号

需要使用到h5的 <a>标签 我们首先在<head>标签中添加代码 <meta name"format-detection" content"telephoneyes"/>然后再想要的位置添加代码 <a href"tel:10086"> 点击拨打&#xff1a;10086 </a> 这样功能就实现…

海量数据处理(面试)

海量数据 1、从大量的URL中找出相同的URL 解法&#xff1a; 分治法&#xff1a; 如果是单个很大的文件&#xff0c;直接划分文件&#xff0c;按特定大小划分&#xff0c;然后多线程&#xff0c;用map对各个文件进行统计。 如果是两个很大的文件&#xff0c;a和b。通过遍历a…

如何在Linux上安装配置Nexus私有仓库

在Linux上安装和配置Nexus私有仓库需要以下步骤&#xff1a; 下载Nexus Repository Manager&#xff1a; 首先&#xff0c;访问Sonatype Nexus官方网站&#xff08;https://www.sonatype.com/nexus-repository-oss&#xff09;并下载适用于Linux的最新版本的Nexus Repository M…

系统架构设计师教程 第4章 信息安全技术基础知识-4.3 信息安全系统的组成框架4.4 信息加解密技术-解读

系统架构设计师教程 第4章 信息安全技术基础知识-4.3 信息安全系统的组成框架 4.3 信息安全系统的组成框架4.3.1 技术体系4.3.1.1 基础安全设备4.3.1.2 计算机网络安全4.3.1.3 操作系统安全4.3.1.4 数据库安全4.3.1.5 终端安全设备4.3.2 组织机构体系4.3.3 管理体系4.4 信息加…

redis命令超详细

redis数据结构介绍 redis是一个key-value的数据库&#xff0c;key一般是String类型&#xff0c;但是value的类型有很多&#xff1a; 基本类型&#xff1a;String,Hash,List,Set,SortedSet(可排序的不能重复的集合) 特殊类型&#xff1a;GEO,BitMap,HyperLog等 文档官网&…

使用编译器指令将此函数定位在指定地址处

#include <stdio.h> // 使用编译器指令将此函数定位在0x08001000地址处 void my_function() attribute((section(“.ARM.__at_0x08001000”))); void my_function() { printf(“Function located at 0x08001000\n”); } int main() { my_function(); return 0; }

emr部署hive并适配达梦数据库

作者&#xff1a;振鹭 一、达梦 用户、数据库初始化 1、创建hive的元数据库 create tablespace hive_meta datafile /dm8/data/DAMENG/hive_meta.dbf size 100 autoextend on next 1 maxsize 2048;2、创建数据库的用户 create user hive identified by "hive12345&quo…

Android --- 广播

广播是什么&#xff1f; 一种相互通信&#xff0c;传递信息的机制&#xff0c;组件内、进程间&#xff08;App之间&#xff09; 如何使用广播&#xff1f; 组成部分 发送者-发送广播 与启动其他四大组件一样&#xff0c;广播发送也是使用intent发送。 设置action&#xff…

如何在Ubuntu上安装并启动SSH服务(Windows连接)

在日常的开发和管理工作中&#xff0c;通过SSH&#xff08;Secure Shell&#xff09;连接到远程服务器是一个非常常见的需求。如果你在尝试通过SSH连接到你的Ubuntu系统时遇到了问题&#xff0c;可能是因为SSH服务未安装或未正确配置。本文将介绍如何在Ubuntu上安装并启动SSH服…

高效工作流:用Mermaid绘制你的专属流程图;如何在Vue3中导入mermaid绘制流程图

目录 高效工作流&#xff1a;用Mermaid绘制你的专属流程图 一、流程图的使用场景 1.1、流程图flowChart 1.2、使用场景 二、如何使用mermaid画出优雅的流程图 2.1、流程图添加图名 2.2、定义图类型与方向 2.3、节点形状定义 2.3.1、规定语法 2.3.2、不同节点案例 2.…