spring Bean 生命周期BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean接口详解

2023-11-19

继续接着上一篇完成后续接口的解析

还是借用上一篇引用大佬的文章:https://www.jianshu.com/p/1dec08d290c1

第二篇spring Bean 生命周期及BeanPostProcessor和InstantiationAwareBeanPostProcessor详解

第二大类:只调用一次的接口(只做用于bean)

这一大类接口的特点是功能丰富,常用于用户自定义扩展。
第二大类中又可以分为两类:

  1. Aware类型的接口
  2. 生命周期接口

无所不知的Aware

Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware可以拿到BeanName,以此类推。调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!
Aware接口众多,这里同样通过分类的方式帮助大家记忆。
Aware接口具体可以分为两组,至于为什么这么分,详见下面的源码分析。如下排列顺序同样也是Aware接口的执行顺序,能够见名知意的接口不再解释。

Aware Group1

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

Aware Group2

  1. EnvironmentAware
  2. EmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
  3. ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口

作者:sunshujie1990
链接:https://www.jianshu.com/p/1dec08d290c1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

我们还是从两个点来分析:

一是何时加入到beanFactory

二是何时调用

先从何时调用开始说明

准备测试代码:按上一节的测试代码测试(spring Bean 生命周期及BeanPostProcessor和InstantiationAwareBeanPostProcessor详解

UserService实现下面的接口重写它们的方法

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware
@Component
public class UserService implements InitializingBean, BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {


	@Autowired
	private Test test;

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("InitializingBean.afterPropertiesSet()-------------");
	}

	public void test() {
		System.out.println("test");
	}

	@Override
	public void setBeanName(String name) {
		System.out.println(name);

	}

	@Override
	public void setBeanClassLoader(ClassLoader classLoader) {
		System.out.println(classLoader);
	}

	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println(beanFactory);
	}
}

还是debug调试,打上各接口重写方法的断点

找到方法的调用点:

	private void invokeAwareMethods(final String beanName, final Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof BeanNameAware) {
				((BeanNameAware) bean).setBeanName(beanName);
			}
			if (bean instanceof BeanClassLoaderAware) {
				ClassLoader bcl = getBeanClassLoader();
				if (bcl != null) {
					((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
				}
			}
			if (bean instanceof BeanFactoryAware) {
				((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
			}
		}
	}

由此可以知道是在invokeAwareMethods方法里面执行,观看源码可以很快的得知这三个Aware的执行顺序依次排序:

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

从第一张图片也可看出跟上一节的BeanPostProcessor执行位置一样都是在

setBeanName:30, UserService (com.luban.service)
invokeAwareMethods:1925, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
initializeBean:1896, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:623, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:528, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
lambda$doGetBean$0:341, AbstractBeanFactory (org.springframework.beans.factory.support)
getObject:-1, 1627821297 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$28)
getSingleton:243, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
doGetBean:339, AbstractBeanFactory (org.springframework.beans.factory.support)
getBean:204, AbstractBeanFactory (org.springframework.beans.factory.support)
preInstantiateSingletons:917, DefaultListableBeanFactory (org.springframework.beans.factory.support)
finishBeanFactoryInitialization:918, AbstractApplicationContext (org.springframework.context.support)
refresh:574, AbstractApplicationContext (org.springframework.context.support)
<init>:107, AnnotationConfigApplicationContext (org.springframework.context.annotation)
main:10, Test (com.luban)

doCreateBean()方法里面(下一节写doCreateBean的源码)

其实就是在初始化new AnnotationConfigApplicationContext(AppConfig.class)时候会去实例化非懒加载的单例bean,在doCreateBean()方法里面有流程规定哪个时候调用上述接口的方法做一些个性化操作。

我这里也实现了InitializingBean方法,继续往下走断点可以看到InitializingBean的方法是执行在上面三个Aware方法之后

再看第二组的Aware

同理UserService实现这个几个接口,打上断点

	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof EnvironmentAware) {
			((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
		}
		if (bean instanceof EmbeddedValueResolverAware) {
			((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
		}
		if (bean instanceof ResourceLoaderAware) {
			((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
		}
		if (bean instanceof ApplicationEventPublisherAware) {
			((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
		}
		if (bean instanceof MessageSourceAware) {
			((MessageSourceAware) bean).setMessageSource(this.applicationContext);
		}
		if (bean instanceof ApplicationContextAware) {
			((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
		}
	}

从上面可以看出也是跟第一组Aware一样,只是先执行完在执行后面的,也是在初始化前。

查看控制台打印日志:

由打印日志可以知道生命周期的执行顺序:

1.InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(Class<?> beanClass, String beanName)
2.InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(Object bean, String beanName)
3.InstantiationAwareBeanPostProcessor.postProcessProperties(PropertyValues pvs, Object bean, String beanName):这里必须上面方法返回true才会执行
4.BeanNameAware.setBeanName(String name);
5.BeanClassLoaderAware.setBeanClassLoader(ClassLoader classLoader);
6.BeanFactoryAware.setBeanFactory(BeanFactory beanFactory)
7.EnvironmentAware.setEnvironment(Environment environment);
8.EmbeddedValueResolverAware.setEmbeddedValueResolver(StringValueResolver resolver);
9.ApplicationContextAware.setApplicationContext(ApplicationContext applicationContext)
10.BeanPostProcessor.postProcessBeforeInitialization(Object bean, String beanName)
11.InitializingBean.afterPropertiesSet()
12.BeanPostProcessor.postProcessAfterInitialization(Object bean, String beanName)
13.DisposableBean.destroy()

何时加入到beanFactory

 

其实何时加入到beanFactory里面,因为Aware是作用到单个bean上面,在实例化非懒加载单例bean的时候调用的,所以何时加入到beanFactory在第一篇已经说了(https://blog.csdn.net/weixin_42955916/article/details/117782347)这里就不说明了

下一节我们来看doCreateBean()方法源码

导航:

1.Spring Bean是怎么被创建进入工厂的

2.spring Bean 生命周期及BeanPostProcessor和InstantiationAwareBeanPostProcessor详解

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring Bean 生命周期BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean接口详解 的相关文章

随机推荐

  • SQL入门书籍内容汇总

    转头一晃 SQL入门书籍看完了 并且在画思维导图和整理笔记的过程中又一次加深了印象 不过也仅仅停留在课本层面上 不进行实际操作终将不知道你有没有学会如何运用 当然肯定不会自己创建一些数据库了 这个事不用质疑的 不过却可以读懂里面的一些用法
  • 【RK3399】I3399烧写Android系统详解

    00 目录 文章目录 00 目录 01 驱动安装 02 Android镜像文件烧写 03 问题讨论 04 附录 01 驱动安装 1 1 没有安装驱动的时候 显示感叹号 1 2 解压DriverAssitant v5 1 1 zip 1 3
  • 展锐8541芯片CPU推理MNN模型加速的若干问题

    一 在只有CPU的嵌入式设备上部署AI模型时 可以采取以下方法来提高模型的运行速度 1 量化模型 将浮点数模型转换为定点数模型 可以减少模型的计算和存储需求 从而提高模型的运行速度 2 剪枝模型 通过删除模型中不必要的连接和神经元 可以减少
  • 如何安装虚拟机?安装虚拟机的详细步骤

    1 下载虚拟机软件 首先 在官方网站上下载需要的虚拟机软件 如VMware VirtualBox等 注意软件版本的兼容性 最好选择最新版本 2 安装虚拟机软件 下载完成后 双击安装文件 按照提示完成安装 期间需要设置虚拟机软件的安装路径等信
  • C语言实现推箱子小游戏

    一 设计目的 用简单的C语言知识制作的推箱子游戏 通过上下左右键将所有箱子移动到目标位置 2 让我们更好地了解和巩固C语言知识 并实际运用 同时运用一些不太常见的知识点 二 功能描述 1 模块功能 本程序可分为初始界面 进行游戏 判定通关三
  • C++ list——push_back()与insert()

    push back 是把插入元素直接放入链表结尾 不多表述 insert 是把元素插入指定位置 摘自MSDN IDE VS2012 Parameters Parameter D
  • 使用UncaughtExceptionHandler进行未知异常得捕获

    UncaughtExceptionHandler UncaughtExceptionHandler使用场景 Thread类源代码 UncaughtExceptionHandler使用代码 UncaughtExceptionHandler使用
  • 场景法

    场景法 通过运用场景来对系统的功能点或业务流程的描述 从而提高测试效果 场景法一般包含基本流和备用流 从一个流程开始 通过描述经过的路径来确定的过程 经过遍历所有的基本流和备用流来完成整个场景 基本流 通过一个正确的事件流实现正确流程 备选
  • chatgpt赋能python:如何用Python实现抢购?

    如何用Python实现抢购 Python是一种灵活多样的编程语言 可以用它来完成各种任务 其中之一就是抢购 在电商大促销的节日 抢购商品通常需要竞争非常激烈 但是使用Python编写抢购脚本可以让您获得更高的成功率 以下是一些建议 通过Py
  • ①GD32Keil编译环境搭建及编译Demo

    进入 兆易官网 下载对应芯片的演示套件 下载解压后文件内容如下 安装keil5 我的keil5 下的pack包 打开demo包下的一个例程 提示如下
  • vue-router 2.0 常用基础知识点之router.push()

    router push location 除了使用
  • 红帽rhce认证考试科目有哪些?

    红帽RHCE认证考试主要考察的科目包括 RH124 主要考察Linux基础 文件和目录管理 用户和组管理 文件和目录权限管理 进程管理 系统服务 网络配置 日志分析等内容 RH134 主要考察自动化安装 文件编辑 任务计划 系统进程优先级管
  • 在Linux中安装Cmake过程中,遇到有关于openSSL的问题

    在Linux中安装Cmake过程中 遇到有关于openSSL的问题 以下是个人在安装cmake的过程中遇到的一些问题 如有什么错误之处欢迎各位大佬留言 共同进步 提示 Could Not Find OpenSSL try to set th
  • 【CV中的Attention机制】模块梳理合集

    文章目录 0 总述 1 SENet CVPR18 2 SKNet CVPR19 3 CBAM ECCV18 BAM BMVC18 scSE MICCAI18 4 Non Local Network CVPR19 5 GCNet ICCVW1
  • 手把手教你爬取并下载英雄联盟所有英雄皮肤高清大图

    利用requests和urlretrieve爬取并下载英雄联盟所有英雄皮肤高清大图 不知道屏幕前的你是不是也是一名loler 最近学习爬虫 印象中以前看过爬取英雄联盟的帖子 所以也就自己试了试 结果很是满意 先上效果图 亲女儿拉克丝 下面开
  • IO多路复用--[select

    因为在简历上写了netty的项目 因此还是将网络底层的那点东西搞清楚 首先希望明确的是 BIO NIO IO多路复用这是不同的东西 我会在本文中详细讲出来 本文参考资料 JAVA IO模型 IO多路复用 select poll epoll介
  • SpringBoot2.2.X整合ElasricSearch7.8

    这里默认大家已经掌握es基础语法 es版本为7 8 pom
  • pikachu靶场&RCE&文件包含&上传下载&越权(四)

    文章目录 RCE 概述 RCE PING RCE EVEL File Inclusion 文件包含漏洞 概述 文件下载漏洞 概念 文件上传漏洞 概述 前端页面检查 client check MIME TYPE漏洞 getimagesize
  • openwrt恢复出厂设置有两种方法

    1 输入以下指令 firstboot mtd r erase rootfs data 2 输入以下指令 mount root firstboot reboot f
  • spring Bean 生命周期BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean接口详解

    继续接着上一篇完成后续接口的解析 还是借用上一篇引用大佬的文章 https www jianshu com p 1dec08d290c1 第二篇spring Bean 生命周期及BeanPostProcessor和Instantiation