Spring-bean的生命周期-尾篇

news/2024/9/20 2:46:27/ 标签: spring, java, 后端

上回说到阶段9,现在我们接着往下说

阶段10:所有单例bean初始化完成后阶段

所有单例bean实例化完成之后,spring会回调下面这个接口:

java">package org.springframework.beans.factory;public interface SmartInitializingSingleton {public void afterSingletonsInstantiated();
}

调用逻辑在下面这个方法中

java">/**
* 确保所有非lazy的单例都被实例化,同时考虑到FactoryBeans。如果需要,通常在工厂设置结束时调用。
*/
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

这个方法内部会先触发所有非延迟加载的单例bean初始化,然后从容器中找到类型是SmartInitializingSingleton 的bean,调用他们的 afterSingletonsInstantiated 方法。

来个案例

java">package com.shiguiwu.springmybatis.spring.lifecycle.allbeaninit;import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** @description: 10所有bean初始化完成* 注意是非懒加载的bean初始化完成* @author: stone* @date: Created by 2021/3/28 13:35* @version: 1.0.0* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.allbeaninit*/
@ComponentScan
public class AllBeanInitTests {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//        Arrays.stream(context.getBeanDefinitionNames()).forEach(b -> System.out.println(context.getBean(b)));context.register(AllBeanInitTests.class);System.out.println("开始启动容器!");context.refresh();System.out.println("容器启动完毕!");}
}

打印结果

java">开始启动容器!
14:00:04.770 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@11438d26
14:00:04.903 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
14:00:05.473 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [G:\workspace\ideaWorkspace\spring-mybatis\target\classes\com\shiguiwu\springmybatis\spring\lifecycle\allbeaninit\Bean1.class]
14:00:05.474 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [G:\workspace\ideaWorkspace\spring-mybatis\target\classes\com\shiguiwu\springmybatis\spring\lifecycle\allbeaninit\Bean2.class]
14:00:05.483 [main] DEBUG org.springframework.context.annotation.ClassPathBeanDefinitionScanner - Identified candidate component class: file [G:\workspace\ideaWorkspace\spring-mybatis\target\classes\com\shiguiwu\springmybatis\spring\lifecycle\allbeaninit\MySmartInitializingSingleton.class]
14:00:05.571 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
14:00:05.586 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
14:00:05.588 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
14:00:05.591 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
14:00:05.673 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'allBeanInitTests'
14:00:05.683 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
14:00:05.683 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
14:00:05.684 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'mySmartInitializingSingleton'
SmartInitializingSingleton#afterSingletonsInstantiated========================
容器启动完毕!

阶段11:Bean使用阶段

这个阶段就不说了,调用getBean方法得到了bean之后,大家可以随意使用,任意发挥。

阶段12:Bean销毁阶段

触发bean销毁的几种方式

  1. 调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyBean
  2. 调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons
  3. 调用ApplicationContext中的close方法

Bean销毁阶段会依次执行

  1. 轮询beanPostProcessors列表,如果DestructionAwareBeanPostProcessor这种类型的,会调用其内部的postProcessBeforeDestruction方法
  2. 如果bean实现了org.springframework.beans.factory.DisposableBean接口,会调用这个接口中的destroy方法
  3. 调用bean自定义的销毁方法

DestructionAwareBeanPostProcessor 接口

java">package org.springframework.beans.factory.config;import org.springframework.beans.BeansException;public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor {//bean销毁前调用的方法void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException;//用来判断bean是否需要触发postProcessBeforeDestruction方法default boolean requiresDestruction(Object bean) {return true;}
}

这个接口有个关键的实现类:

java">org.springframework.context.annotation.CommonAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor#postProcessBeforeDestruction方法中会调用bean中所有标注了@PreDestroy的方法。

再来说一下自定义销毁方法有3种方式
方式1:xml中指定销毁方法

<bean destroy-method="bean中方法名称"/>

方式2:@Bean中指定销毁方法

java">@Bean(destroyMethod = "初始化的方法")

方式3:api的方式指定销毁方法

this.beanDefinition.setDestroyMethodName(methodName);

初始化方法最终会赋值给下面这个字段

java">org.springframework.beans.factory.support.AbstractBeanDefinition#destroyMethodName

来个案例

java">package com.shiguiwu.springmybatis.spring.lifecycle.destroy;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;/*** @description: 销毁时调用的代码* @author: stone* @date: Created by 2021/3/28 14:55* @version: 1.0.0* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.destroy*/
public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {System.out.println("准备销毁bean:" + beanName);}@Overridepublic boolean requiresDestruction(Object bean) {System.out.println("是否调用。。。。。。。");return true;}
}

测试代码

java">package com.shiguiwu.springmybatis.spring.lifecycle.destroy;import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;/*** @description: 12销毁阶段** 1. 调用* org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#destroyB* ean* 2. 调用org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons* 3. 调用ApplicationContext中的close方法** 顺序* 1. @PreDestroy标注的所有方法* 2. DisposableBean接口中的destroy()* 3. 自定义的销毁方法* @author: stone* @date: Created by 2021/3/28 13:59* @version: 1.0.0* @pakeage: com.shiguiwu.springmybatis.spring.lifecycle.destroy*/
public class DestroyTests {public static void main(String[] args) {DefaultListableBeanFactory factory = new DefaultListableBeanFactory();factory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());//将CommonAnnotationBeanPostProcessor加入factory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor()); //@2AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(Integer.class).addConstructorArgValue(12).getBeanDefinition();AbstractBeanDefinition definition1 = BeanDefinitionBuilder.genericBeanDefinition(Integer.class).addConstructorArgValue(12).getBeanDefinition();AbstractBeanDefinition definition3 = BeanDefinitionBuilder.genericBeanDefinition(A.class).getBeanDefinition();//设置销毁方法definition3.setDestroyMethodName("destroy1");factory.registerBeanDefinition("shuzi", definition);factory.registerBeanDefinition("shuzi1", definition1);factory.registerBeanDefinition("A", definition3);//触发所有单列初始化factory.preInstantiateSingletons();//销毁一个factory.destroySingleton("shuzi");System.out.println("销毁所有的bean");factory.destroySingletons();//关闭容器}
}

打印结果

java">14:29:38.611 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'shuzi'
是否调用。。。。。。。
是否调用。。。。。。。
14:29:38.922 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'shuzi1'
是否调用。。。。。。。
是否调用。。。。。。。
14:29:38.923 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'A'
是否调用。。。。。。。
准备销毁bean:shuzi
销毁所有的bean
准备销毁bean:A
preDestroy() 
destroy() 
destroy1() 自定义的。。。。。。。。 
准备销毁bean:shuzi1

实际上ApplicationContext内部已经将spring内部一些常见的必须的 BeannPostProcessor 自动装配到beanPostProcessors列表中 ,比如我们熟悉的下面的几个

1.org.springframework.context.annotation.CommonAnnotationBeanPostProcessor用来处理@Resource、@PostConstruct、@PreDestroy的
2.org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor用来处理@Autowired、@Value注解
3.org.springframework.context.support.ApplicationContextAwareProcessor
用来回调Bean实现的各种Aware接口

下面来说一个非常非常重要的类,打起精神,一定要注意看。
AbstractApplicationContext类(非常重要的类)
image.png

BeanFactory接口
这个我们已经很熟悉了,Bean工厂的顶层接口
DefaultListableBeanFactory类
实现了BeanFactory接口,可以说这个可以是BeanFactory接口真正的唯一实现,内部真正实现了bean生命周期中的所有代码。其他的一些类都是依赖于DefaultListableBeanFactory类,将请求转发给DefaultListableBeanFactory进行bean的处理的。
其他3个类
我们经常用到的就是这3个类:
AnnotationConfigApplicationContext/ClassPathXmlApplicationContext/FileSystemXmlApplicationContext这3个类,他们的主要内部的功能是依赖他的父类AbstractApplicationContext来实现的,所以大家主要看AbstractApplicationContext 这个类。

AbstractApplicationContext类
这个类中有2个比较重要的方法

java">public abstract ConfigurableListableBeanFactory getBeanFactory() throws
IllegalStateException;
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory
beanFactory)

大家是否注意过我们使用 AnnotationConfigApplicationContext 的时候,经常调用 refresh方法 ,这个方法内部就会调用上面这2个方法

第一个方法:getBeanFactory()
返回当前应用上下文中的 ConfigurableListableBeanFactory ,这也是个接口类型的,这个接口有一个唯一的实现类: DefaultListableBeanFactory 。有没有很熟悉,上面说过:DefaultListableBeanFactory是BeanFactory真正的唯一实现。应用上线文中就会使用这个 ConfigurableListableBeanFactory 来操作spring容器。

第二个方法:registerBeanPostProcessors
说的通俗点:这个方法就是向ConfigurableListableBeanFactory中注册BeanPostProcessor,内容会从spring容器中获取所有类型的BeanPostProcessor,将其添加到DefaultListableBeanFactory#beanPostProcessors列表中

看一下这个方法的源码:

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

会将请求转发给PostProcessorRegistrationDelegate#registerBeanPostProcessors 。内部比较长,大家可以去看一下源码,这个方法内部主要用到了4个BeanPostProcessor 类型的List集合。

List priorityOrderedPostProcessors = new ArrayList<>();
List orderedPostProcessors
List nonOrderedPostProcessors;
List internalPostProcessors = new ArrayList<>();

先说一下:当到方法的时候,spring容器中已经完成了所有Bean的注册。
spring会从容器中找出所有类型的BeanPostProcessor列表,然后按照下面的规则将其分别放到上面的4个集合中,上面4个集合中的 BeanPostProcessor 会被依次添加到DefaultListableBeanFactory#beanPostProcessors列表中,来看一下4个集合的分别放的是那些BeanPostProcessor

priorityOrderedPostProcessors(指定优先级的BeanPostProcessor)
实现org.springframework.core.PriorityOrdered接口的BeanPostProcessor,但是不包含MergedBeanDefinitionPostProcessor类型的
orderedPostProcessors(指定了顺序的BeanPostProcessor)
实现了org.springframework.core.annotation.Order接口的BeanPostProcessor,但是不包含MergedBeanDefinitionPostProcessor类型的
nonOrderedPostProcessors(未指定顺序的BeanPostProcessor)
上面2中类型置为以及MergedBeanDefinitionPostProcessor之外的internalPostProcessors
MergedBeanDefinitionPostProcessor类型的BeanPostProcessor列表。

大家可以去看一下 CommonAnnotationBeanPostProcessor 和
AutowiredAnnotationBeanPostProcessor ,这两个类都实现了 PriorityOrdered 接口,但是他们也实现了MergedBeanDefinitionPostProcessor 接口,所以最终他们会被丢到
internalPostProcessors 这个集合中,会被放入BeanPostProcessor的最后面。

此致,spring bean生命周期完整的流程结束,附上完整的流程图!!完结,我好累
微信图片_20211104122611.jpg


http://www.ppmy.cn/news/1527856.html

相关文章

150+个流行的Instagram标签(及如何找到并正确使用它们)

早在2007年8月&#xff0c;当你还在收音机里唱着“Umbrella”&#xff08;ella…ella&#xff09;的时候&#xff0c;一位名叫Chris Messina的产品设计师向Twitter提出了“使用#&#xff08;井号&#xff09;来分组”的想法。 Twitter的回应是什么&#xff1f;太书呆子气&#…

Cassandra 和 ScyllaDB

Cassandra 和 ScyllaDB 详解 Cassandra 和 ScyllaDB 是现代分布式数据库系统中非常受欢迎的两个选择&#xff0c;它们在性能、可扩展性和高可用性方面有着显著优势&#xff0c;适合大规模、高吞吐量的应用场景。这两者都是面向列的分布式数据库&#xff08;Columnar Store&…

详解TCP的三次握手

TCP&#xff08;三次握手&#xff09;是指在建立一个可靠的传输控制协议 (TCP) 连接时&#xff0c;客户端和服务器之间的三步交互过程。这个过程的主要目的是确保连接是可靠的、双方的发送与接收能力是正常的&#xff0c;并且可以开始数据传输。下面是对每个步骤的详细解释&…

C++ | Leetcode C++题解之第406题根据身高重建队列

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {sort(people.begin(), people.end(), [](const vector<int>& u, const vector<int>& v) …

VirtualBox增加磁盘并给docker用

在VirtualBox新增磁盘 在虚拟机停止的情况下依次选择&#xff0c;然后创建新磁盘 虚拟机新磁盘创建分区、格式化、挂载分区 开机自动挂载新磁盘分区/dev/sdb1&#xff1a; nano /etc/fstab末尾添加一行&#xff1a; /dev/sdb1 /disk02 e…

深入理解ConcurrentHashMap

HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进行put操作&#xff0c;调用了HashMap的putVal()&#xff0c;具体原因&#xff1a; 假设两个线程A、B都在进行put操作&#xff0c;并且hash函数计算出的插入下标是相同的&#xff1b; 当线程A执行完第六行由于时间片…

linux-Linux 内核与模块管理-内核基础

Linux 内核是操作系统的核心&#xff0c;它负责管理硬件资源和提供系统调用接口供用户程序使用。Linux 内核的设计极为灵活和模块化&#xff0c;它允许开发者通过加载和卸载模块来动态地扩展内核的功能。 一、Linux 内核概述 1.1 内核的基本功能 Linux 内核的主要功能可以分…

Python基础语法(3)下

列表和元组 列表是什么&#xff0c;元组是什么 编程中&#xff0c;经常需要使用变量&#xff0c;来保存/表示数据。变量就是内存空间&#xff0c;用来表示或者存储数据。 如果代码中需要表示的数据个数比较少&#xff0c;我们直接创建多个变量即可。 num1 10 num2 20 num3…

【计算机网络】数据链路层深度解析

概述三个重要问题封装成帧差错检测可靠传输 使用广播信道的数据链路层数据链路层的互连设备 媒体接入MAC地址集线器与交换机区别以太网交换机生成树协议STP 概述 链路就是从一个结点到相邻结点的一段物理线路&#xff0c;而中间没有任何其他的交换结点。数据链路是指把实现通信…

数据结构-3.3.栈的链式存储实现

一.链栈的定义&#xff1a; 二.总结&#xff1a;

【C++算法】模拟算法

替换所有的问号 题目链接 替换所有的问号https://leetcode.cn/problems/replace-all-s-to-avoid-consecutive-repeating-characters/description/ 算法原理 代码步骤 class Solution { public:string modifyString(string s) {int n s.size();for(int i 0; i < n; i){…

面试爱考 | 设计模式

一、概述二、创建型 1. 单例&#xff08;Singleton&#xff09; IntentClass DiagramImplementationExamplesJDK 2. 简单工厂&#xff08;Simple Factory&#xff09; IntentClass DiagramImplementation 3. 工厂方法&#xff08;Factory Method&#xff09; IntentClass Diagr…

Halo 开发者指南——项目运行、构建

准备工作 环境要求 OpenJDK 17 LTSNode.js 20 LTSpnpm 9IntelliJ IDEAGitDocker&#xff08;可选&#xff09; 名词解释 工作目录 指 Halo 所依赖的工作目录&#xff0c;在 Halo 运行的时候会在系统当前用户目录下产生一个 halo-next 的文件夹&#xff0c;绝对路径为 ~/ha…

钻机、塔吊等大型工程设备,如何远程维护、实时采集运行数据?

在建筑和工程领域&#xff0c;重型设备的应用不可或缺&#xff0c;无论是在道路与桥梁建设、高层建筑施工&#xff0c;还是在风电、石油等能源项目的开发中&#xff0c;都会用到塔吊、钻机等大型机械工程设备。 随着数字化升级、工业4.0成为行业发展趋势&#xff0c;为了进一步…

MacOS安装homebrew,jEnv,多版本JDK

1 安装homebrew homebrew官网 根据官网提示&#xff0c;运行安装命令 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装后&#xff0c;bash会提示执行两条命令 (echo; echo eval "$(/opt/homebrew/b…

海外问卷调查是做什么的,适合什么人做

疫情结束后的市场大环境萧条&#xff0c;特别是实体经济&#xff0c;许多中小微企业要么倒闭&#xff0c;要么垂死挣扎&#xff0c;等待重生。于是有一些老板&#xff0c;就转型做起了互联网生意。 抖音这几年的直播带货、短视频带货等等飞速崛起&#xff0c;成就了多少百万富…

如何用站群服务器做抢购秒杀平台

随着各种电商购物节的开幕&#xff0c;全球外贸、直播电商抢购活动愈发火热&#xff0c;外贸行业容纳了海量的公司、组织和个人。为了营销&#xff0c;人们使用海外站群服务器抢货的做法已经不再稀奇&#xff0c;因为使用海外站群服务器操作抢购秒杀商品&#xff0c;可以拥有多…

爬坑--docker构建容器ssh连接容器环境变量会发生变化

问题 通过 Dockerfile 语句在镜像中安装了 openssh, 但是在创建容器之后, 通过 docker exec -it 容器 bash 和通过远程 ssh, 会发现两边终端的 PATH 不一致, ssh 连接明显缺少一些东西. 解决方案 在 Dockerfile 最后添加: RUN echo "export PATH${PATH}" >>…

适合博客的组件库

在选择适合博客的组件库时&#xff0c;需要考虑博客的主题、内容类型以及预期的用户体验。以下是一些推荐的组件库&#xff0c;它们各自具有独特的特点和优势&#xff0c;能够帮助你提升博客的视觉效果和用户体验&#xff1a; React Markdown&#xff1a;非常适合技术博客和教…

图新地球-将地图上大量的地标点批量输出坐标到csv文件【kml转excel】

0.序 有很多用户需要在卫星影像、或者无人机航测影像、倾斜模型上去标记一些地物的位置&#xff08;如电线杆塔、重点单位、下水盖等&#xff09; 标记的位置最终又需要提交坐标文本文件给上级单位或者其他部门使用&#xff0c;甚至需要转为平面直角坐标。 本文的重点是通过of…