3分钟秒懂,最简单通俗易懂的spring bean 生命周期介绍与源码分析,附上demo完整源码

news2024/12/28 3:55:41

文章写作背景

最近突然身边很多小伙伴问我有没有spring bean生命周期的通俗移动的介绍
起初不太理解为什么,后来才想明白,哦对了,年底了,快开始跳槽季了,这不就是java八股文面试
的题目嘛,不得不说,国内真的很卷,之前有认识的外国友人,人家说面试根本不会问这些,基本就是
问问做过哪些项目,功能,模块就完事了,主要是试用期去衡量他的能力,好了闲话少说,我们开始
正式聊一聊spring bean 的生命周期,本文不涉及循环依赖以及三级缓存问题,如果需要的话,我可以后续有时间的时候单独写一篇介绍,本文只针对bean的生命周期,尽量用最简化的方式描述

为什么大家有时候觉得spring bean的生命周期繁琐

其实我觉得大家是把主流程和分支流程搞一起了,网上大部分文章都是混在一起介绍的,比如创建实例createBeanInstance之前会执行
InstantiationAwareBeanPostProcessor的postProcessBeforeInitialization方法,
创建之后还会执行MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法然后执行 InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法
其实这些大家不需要和主流程混在一起记忆,因为这些都是辅助分支流程,因为可能你定义多少
实现类那就是多少辅助流程循环执行

真正的spring bean 主生命周期

其实真正的spring bean 生命周期大家只要记住是生成实例->填充属性->初始化->销毁就可以了

如何记忆before after merge等辅助流程

为了方便大家记忆,我特意画了一个流程图,主流程和辅助流程是分开的,一目了然,再结合我下面的demo,跑一下程序或者自己写一个验证一下就可以了,如图下:
在这里插入图片描述

创建简单demo 实现各个辅助接口完整源码

目录结构

在这里插入图片描述

pom引用

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
            <scope>compile</scope>
        </dependency>

创建空项目,引入spring-contenxt,为什么引入context,因为它包含了spring framework 基本的所有依赖pom

Application.java

/**
 * @Author alan.wang
 */
public class Application {

    public static Integer index = 0;

    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Teacher teacher = context.getBean(Teacher.class);
        System.out.println("class:" + teacher.name());
    }
}

Teacher.java 以及TeacherImpl.java 实现类
TeacherImpl 实现了上图那些接口InitializingBean,BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,DisposableBean

/**
 * @Author alan.wang
 */
public interface Teacher {
    String name();
}


/**
 * @Author alan.wang
 */
@Service
public class TeacherImpl implements Teacher  , InitializingBean, BeanNameAware, BeanClassLoaderAware, BeanFactoryAware , DisposableBean {


    public String name() {
        return "teacher";
    }


    @PostConstruct
    public void init(){
        System.out.println(++Application.index+" postConstruct");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println(++Application.index+" afterPropertiesSet");
    }

    public void setBeanName(String name) {
        System.out.println(++Application.index+" setBeanName");
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println(++Application.index+" setBeanClassLoader");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println(++Application.index+" setBeanFactory");
    }


    @Override
    public void destroy() throws Exception {
        System.out.println(++Application.index+" destroy");

    }
}

PrintAwareBeanPostProcessor.java
PrintAwareBeanPostProcessor实现了InstantiationAwareBeanPostProcessor 接口主要是对类创建实例前和后的包装
这里就是单纯地输出,证明执行了

/**
 * @Author alan.wang
 */
@Service
public class PrintAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println(++Application.index+" InstantiationAwareBeanPostProcessor-postProcessBeforeInstantiation:"+beanName);
        return null;
    }

    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println(++Application.index+" InstantiationAwareBeanPostProcessor-postProcessAfterInstantiation:"+beanName);

        return true;
    }

    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println(++Application.index+ " InstantiationAwareBeanPostProcessor-postProcessProperties:"+beanName);

        return pvs;
    }
}

PrintMergedBeanDefinitionPostProcessor.java
PrintMergedBeanDefinitionPostProcessor
实现了MergedBeanDefinitionPostProcessor 接口,主要是对实例化后的bean进行自定义的mergec处理
这里仅仅是对方法进行输出

/**
 * @Author alan.wang
 */
@Component
public class PrintMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        System.out.println(++Application.index+" MergedBeanDefinitionPostProcessor-postProcessMergedBeanDefinition:"+beanName);
    }

    public void resetBeanDefinition(String beanName) {
        System.out.println(++Application.index+" MergedBeanDefinitionPostProcessor-resetBeanDefinition:"+beanName);

    }
}


> ***PrintBeanPostProcessor.java
> PrintBeanPostProcessor实现了BeanPostProcessor接口 BeanPostProcessor实际上是根接口,InstantiationAwareBeanPostProcessor和MergedBeanDefinitionPostProcessor都是它的子接口
> BeanPostProcessor 一般是对bean 初始化阶段的前后before 和after处理
> 这里也仅仅是方法输出***
/**
 * @Author alan.wang
 */
@Service
public class PrintBeanPostProcessor implements BeanPostProcessor  {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(++Application.index+" BeanPostProcessor-postProcessBeforeInitialization:"+beanName);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(++Application.index+" BeanPostProcessor-postProcessAfterInitialization:"+beanName);
        return bean;
    }
}

demo 执行结果与并对照上面的流程图来看源码

首先来看下执行输出执行顺序结果
在这里插入图片描述

我们看到首先执行的是InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法
该方法是在创建bean的实例之前的,源码如下:

在这里插入图片描述

然后是创建bean实例
在这里插入图片描述

然后是填属性,也就是依赖注入
在这里插入图片描述

然后是MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法
在这里插入图片描述

然后是InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法
在这里插入图片描述

然后是InstantiationAwareBeanPostProcessor的postProcessProperties方法
在这里插入图片描述

然后是BeanNameAware的setBeanName 方法 然后是BeanClassLoaderAware的setBeanClassLoader方法
然后是BeanFactoryAware的setBeanFactory 方法,他们可以看做是一体的

在这里插入图片描述

然后是BeanPostProcessor的postProcessBeforeInitialization方法
在这里插入图片描述

然后是@postConstruct注解的方法
在这里插入图片描述

然后是执行初始化函数
在这里插入图片描述

然后是InitializingBean的afterPropertiesSet方法
在这里插入图片描述

然後是BeanPostProcessor的postProcessAfterInitialization方法
在这里插入图片描述

然后是destory 相关,destory实际上demo不会触发,因为执行结束了主线程结束就关闭了,需要一个CloseEvent消息,需要添加addShutdownHook 这里暂时不做介绍
在这里插入图片描述

结束语

不要死记硬背,不要被辅助流程干扰,结合上述流程图去看源码,跑遍demo基本就了解了

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

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

相关文章

【5G RRC】Master Information Block (NR-MIB)

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

手把手教你分析 Linux 启动流程

下载 Linux 内核网址: https://www.kernel.org/ 常用 Linux 内核源码为 4.14、4.19、4.9、5.10、5.15、6.1 等版本,其中 4.14 版本源码压缩包大概 90+M,解压后 700+M,合计 61350 个文件。如此众多的文件,用 source insight 或者 VSCode 查看都会比较卡,所以可以采用在线…

计算机网络第四章

1.网络层主要任务是把分组从源端传到目的端&#xff0c;为分组交换网上的不同主机提供通信服务&#xff0c;网络层传输单位是数据报三个功能&#xff1a;路由选择与分组转发&#xff08;最佳路径&#xff09;异构网络互联拥塞控制数据交换方式三种交换方式&#xff1a;电路交换…

一动不动是王八?动态内存有话说

文章目录前言动态内存函数介绍mallocfreecallocrealloc柔性数组柔性数组特点柔性数组的优点方便内存释放提高我们的访问速度总结前言 一动不动是王八&#xff0c;出自2014年的春晚&#xff0c;小时候经常喜欢说这句话&#xff0c;那在我们C语言中&#xff0c;我们知道&#xf…

年度征文|一个业余电脑玩家的30年(1992-2022)

《论语为政》&#xff1a;“五十而知天命”。岁月真的是一把刀&#xff0c;一晃已过不惑之年&#xff0c;还有几天就要进入知非之年。不论知非还是知天命&#xff0c;反正是花甲将至而从心所欲了。年少时因某种不合机缘&#xff0c;错与IT界擦肩而过&#xff0c;每每想起就扼腕…

gradel学习+IDEA配置

Gradle的下载 Gradle下载地址如下 https://gradle.org/releases/ 我自己的下载的7.4.2 可以选择下载完整的压缩包&#xff0c;将压缩包解压到自己指定的目录中即可。 Gradle安装 1、配置系统变量 GRADLE_HOME 2、配置环境变量 %GRADLE_HOME%是获取变量名称为GRADLE_HOME的…

项目看板开发经验分享(一)——光伏绿色能源看板

今天新开一个系列&#xff0c;专门介绍近期工作中开发的几个比较酷炫的看板的开发思路与经验分享。第一节我们就来介绍下这个光伏绿色能源看板&#xff0c;整体浏览如下&#xff1a; 那就直接进入正题吧—— 0、可复用组件panel 在讲解各个模块之前&#xff0c;我们先来完成一…

Mybatis 框架下 SQL 注入攻击的 3 种方式

SQL注入漏洞作为WEB安全的最常见的漏洞之一&#xff0c;在java中随着预编译与各种ORM框架的使用&#xff0c;注入问题也越来越少。 新手代码审计者往往对Java Web应用的多个框架组合而心生畏惧&#xff0c;不知如何下手&#xff0c;希望通过Mybatis框架使用不当导致的SQL注入问…

Node.js学习笔记

Node.js学习笔记 浏览器的内核包括两部分核心&#xff1a;DOM渲染引擎、JavaScript解析引擎。脱离浏览器环境也可以运行JavaScript&#xff0c;只要有JavaScript引擎就可以。 Node.js是一个基于Chrome V8引擎的JavaScript运行环境。Node.js内置了Chrome的V8 引擎&#xff0c;…

SpringBoot项目部署

系列文章目录 Spring Boot[概述、功能、快速入门]_心态还需努力呀的博客-CSDN博客 Spring Boot读取配置文件内容的三种方式_心态还需努力呀的博客-CSDN博客 Spring Boot整合Junit_心态还需努力呀的博客-CSDN博客 Spring Boot自动配置--如何切换内置Web服务器_心态还需努力呀…

Open3D SOR滤波(Python版本)

文章目录一、简介二、实现代码三、实现效果参考资料一、简介 SOR滤波过程相对简单&#xff0c;其原理是通过查询点与邻域点集之间的距离统计判断来进行过滤离群点。假设一个点的邻近点集符合正太分布&#xff0c;因此我们可以通过计算出该点到它所有临近点的平均距离meanD和标准…

国内怎么体验openAI chatGPT

怎么体验openAI chatGPT 一&#xff0c;前提 1&#xff0c;先准备好一个gmai的邮箱&#xff0c;注册时要用 2&#xff0c;&#xff08;懂得都懂&#xff09; 3&#xff0c;ChatGPT&#xff1a;网址 二&#xff0c;开始注册 1,sign up&#xff0c;用Gmail注册&#xff0c;我…

洛谷P8942 Digital Fortress

题目大意 给定一个区间&#xff0c;构造一个单调不减的序列&#xff0c;使得其前缀异或和与后缀异或和均单调递减&#xff0c;判断这种序列是否存在并输出任意一种解。 思路 暴力 dfs 当然会 TLE,所以我们要仔细分析&#xff1a; ① 在什么情况下异或和能够单调不减&#x…

2023/1/15 JS-原型与原型链

1 什么是原型 原型是Javascript中的继承的基础&#xff0c;JavaScript的继承就是基于原型的继承。每一个JS对象都可以获得自己的原型&#xff0c;通过原型可以共享函数对象和实例对象之间的属性和方法。 原型的出现&#xff0c;就是为了解决 构造函数 的缺点&#xff1a; 每一…

HTB-Shoppy

HTB-Shoppy信息收集开机提权信息收集 22和80。 能扫描出来的东西很杂&#xff0c;但是admin和login可以重点关注。 访问其中之一&#xff0c;能发现是一个登陆界面。 对其进行简单的sql注入测试。输入admin’or11#会出现504超时&#xff0c;判断可能是因为有sql防御措施所致。…

SpringCloud Netflix复习之Zuul

文章目录写作背景Zuul是什么Zuul的核心功能上手实战SpringCloud中Zuul如何使用自定义过滤器配置全局Fallback降级Zuul请求头Ribbon等其他参数配置过滤敏感请求头参数配置开启Ribbon懒加载和Ribbon超时配置开启Hystrix超时配置(一般不配置没啥用)源码部分请求入口ZuulServlet注入…

C++入门--list

目录 list的介绍&#xff1a; list的构造&#xff1a; 遍历&#xff1a; reverse、sort、unique list的模拟实现&#xff1a; 反向迭代器&#xff1a; list与vector的比较&#xff1a; list的介绍&#xff1a; list是序列容器&#xff0c;允许在序列内的任何位置执行O(…

RocketMQ源码(19)—Broker处理DefaultMQPushConsumer发起的拉取消息请求源码【一万字】

基于RocketMQ release-4.9.3&#xff0c;深入的介绍了Broker处理DefaultMQPushConsumer发起的拉取消息请求源码。 此前我们学习了RocketMQ源码(18)—DefaultMQPushConsumer消费者发起拉取消息请求源码。我们知道consumer在发送了拉取消息请求的时候&#xff0c;请求的Code为PUL…

【 JavaScript编程详解 -1 】什么是JavaScript ?

文章目录简介Java与JavaScript的不同Javascrpt可以做什么JavaScript的构成为什么可以在浏览器中运行如何将 JavaScript 代码添加到网站&#xff1f;方法1- \<script\>标签内嵌JavaScript方法1- \<script\>标签引入外部JavaScript文件方法3- 内联 JavaScript编辑器推…

蛇形矩阵(简单明了的方法)

T112524 【数组2】蛇形矩阵 题目来源 AC代码 #include<stdio.h>int main() {int arr[111][111];int n 0;scanf("%d",&n);int temp 0;int sum 1;while(temp<(2*n-2)){for(int i0;i<n;i){for(int j0;j<n;j){if((ij) temp){if(temp%2 0){arr[…