SpringBean-生命周期

Spirng Bean 元信息配置阶段

1 面向资源

  • xml配置(很熟悉了不做讨论)
  • Properties配置
public class BeanMetaDemo {public static void main(String[] args) {DefaultListableBeanFactory factory = new DefaultListableBeanFactory();PropertiesBeanDefinitionReader reader = new PropertiesBeanDefinitionReader(factory);Resource resource = new ClassPathResource("/meta-info/person.properties");// 解决乱码的问题EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");int i = reader.loadBeanDefinitions(encodedResource);Object person = factory.getBean("person");System.out.println(person);}
}
person.(class)=pojo.Person
person.id=10010
person.name=李勇

2 面向注解
3 面向API

Bean 元信息解析

1 面向资源BeanDefiniton 解析

  • BeanDefinitonReader
  • xml 解析器 BeanDefinitionParser
    2 面向注解BeanDefiniton
  • AnnotatedBeanDefinitonReader
// 基于注解的APIBean注册
public class AnnotatedBeanDefinitionParsingDemo {public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(beanFactory);int beforeCount = beanFactory.getBeanDefinitionCount();reader.register(AnnotatedBeanDefinitionParsingDemo.class);int afterCount = beanFactory.getBeanDefinitionCount();System.out.println(afterCount - beforeCount);AnnotatedBeanDefinitionParsingDemo bean = beanFactory.getBean(AnnotatedBeanDefinitionParsingDemo.class);System.out.println(bean);}

Bean注册阶段

BeanDefinitionregistery

@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {Assert.hasText(beanName, "Bean name must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");if (beanDefinition instanceof AbstractBeanDefinition) {try {((AbstractBeanDefinition) beanDefinition).validate();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,"Validation of bean definition failed", ex);}}BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);if (existingDefinition != null) {if (!isAllowBeanDefinitionOverriding()) {throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);}else if (existingDefinition.getRole() < beanDefinition.getRole()) {// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTUREif (logger.isInfoEnabled()) {logger.info("Overriding user-defined bean definition for bean '" + beanName +"' with a framework-generated bean definition: replacing [" +existingDefinition + "] with [" + beanDefinition + "]");}}else if (!beanDefinition.equals(existingDefinition)) {if (logger.isDebugEnabled()) {logger.debug("Overriding bean definition for bean '" + beanName +"' with a different definition: replacing [" + existingDefinition +"] with [" + beanDefinition + "]");}}else {if (logger.isTraceEnabled()) {logger.trace("Overriding bean definition for bean '" + beanName +"' with an equivalent definition: replacing [" + existingDefinition +"] with [" + beanDefinition + "]");}}this.beanDefinitionMap.put(beanName, beanDefinition);}else {// 线程安全if (hasBeanCreationStarted()) {// Cannot modify startup-time collection elements anymore (for stable iteration)synchronized (this.beanDefinitionMap) {this.beanDefinitionMap.put(beanName, beanDefinition);List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);// 保证顺序updatedDefinitions.addAll(this.beanDefinitionNames);updatedDefinitions.add(beanName);this.beanDefinitionNames = updatedDefinitions;removeManualSingletonName(beanName);}}else {// Still in startup registration phasethis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);removeManualSingletonName(beanName);}this.frozenBeanDefinitionNames = null;}if (existingDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);}}

BeanDefinition 合并阶段

BeanDefinition#getParentName
在这里插入图片描述
在xml里面是通过这个属性来配置的,所以需要classloader的参与:
在这里插入图片描述

在注解其实本身就包含了继承关系,可以直接拿到父类信息。

1 没有父类了已经RootBeanDefinition 不需要合并
2 普通的BeanDefinition为GenericBeanDefinition需要合并
合并过程中GenericBeanDefinition->RootBeanDefinition
在这里插入图片描述

代码贴士:ConcurrentHashMap虽然是线程安全的但是只针对于单个操作,get和put,如果有多个get,put操作一起也不能保证是线程安全的。

Bean Class 加载

这里返回的是一个文本BeanDefinition#getBeanClassName
在这里插入图片描述AbstractAutowireCapableBeanFactory#createBean
在这里插入图片描述
org.springframework.beans.factory.support.AbstractBeanDefinition#resolveBeanClass

在这里插入图片描述

this.beanClass 之前是字符串类型,在处理完毕以后是Class类型。

Bean实例化前阶段

InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
通常用于替换之前的实现类,绕开Spring的实例化。

public class BeanInstantiationLifeCycleDemo {@Beanpublic Person person() {Person person = new Person();person.setName("liyong");person.setId(11L);return person;}public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();context.register(BeanInstantiationLifeCycleDemo.class);DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();beanFactory.addBeanPostProcessor(new MyPostProcessBeforeInstantiation());context.refresh();Object person = context.getBean("person");System.out.println(person);}static class MyPostProcessBeforeInstantiation implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {// 实例化之前执行 如果说满足条件直接替换之前的实现if (ObjectUtils.nullSafeEquals("person", beanName) && Person.class.equals(beanClass)) {Person person = new Person();person.setId(11L);person.setName("person");return person;}return null;}}
}

在这里我们返回了我们创建的对象,所以后面的操作不再进行了:
在这里插入图片描述

Spring Bean 实例化阶段

实例化方式

  • 传统方式
  • 实例化策略InstantitaionStrategy
    构造器依赖注入

InstantitaionStrategy有两种实现方法
1 传统的实现方法
AbstractAutowireCapableBeanFactory#createBeanInstance
在这里插入图片描述

2 特殊的实现方法

Spring Bean 实例化后阶段

这里控制了对象实例化以后是否对属性进行赋值:
InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation

@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {// 这里就可以注入我们自己的值,这里和前面before的区别就是 这里我们对象已经被创建了,我们是在已经创建好的对象给它改变属性值if (ObjectUtils.nullSafeEquals("person", beanName) && Person.class.equals(bean.getClass())) {Person person = (Person) bean; person.setId(11L);person.setName("person");return false;}return true;
}

在这里插入图片描述
在这里我们返回了false,所以后面操作不会执行了,而后面的操作也就是赋值属性。

Spring Bean 属性赋值前阶段

Bean 属性值元信息

  • PropertyValues

Bean属性值前回调

  • InstantiationAwareBeanPostProcessor#postProcessPropertyValues 注意到在高版本的Spring 这个方法已经被打上了过时的标签
  • InstantiationAwareBeanPostProcessor#postProcessProperties (5.1及以后)

如果我们希望拦截属性赋值操作

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {// 这里就可以注入我们自己的值 需要注意如果我们postProcessAfterInstantiation 已经返回了false这里就不会执行if (ObjectUtils.nullSafeEquals("person", beanName) && Person.class.equals(bean.getClass())) {MutablePropertyValues propertyValues = new MutablePropertyValues();propertyValues.add("number", "1111");return propertyValues;}return pvs;
}

Spring 生命周期 Aware 接口的顺序

其实顺序就是下面这个顺序:
在这里插入图片描述
我们可以看到源码中的调用顺序:
在这里插入图片描述
EnvironmentAware 以及后面的接口都是属于ApplicationContext的生命周期,普通的BeanFactory 并不会回调这些Aware接口,在操作ApplicationContext的时候才会回调这些接口,因为在ApplicationContext初始化阶段,会添加一个AwarePostProcessor但是这个类是内置类,所以只有与ApplicationContext打交道才会有更多的Aware接口方法回调。

SpirngBean初始化 前阶段

在前面的讨论,已经完成了以下工作,这些工作也是属于前阶段
在这里插入图片描述
InstantiationAwareBeanPostProcessor#postProcessBeforeInitialization

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {}

源码是在这里进行应用的:
在这里插入图片描述

AbstractApplicationContext#prepareBeanFactory
在这里插入图片描述

SpringBean 初始化阶段

他们的执行顺序就是下面的执行顺序
在这里插入图片描述
@PostConstruct 是依赖于注解驱动的,如果通过xml的方式是不会触发的,因为没有对应的PostProcessor。如果我们需要这个生效

beanFactory.addBeanPostProcessor(new CommonAnnotationPostProcessor());

自定义方法是通过xml init-method来进行配置。
AbstractAutowireCapableBeanFactory#initializeBean
实际上PostConstruct是在这个方法applyBeanPostProcessorsBeforeInitialization进行触发的
在这里插入图片描述

初始化后阶段

BeanPostProcessor#postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return InstantiationAwareBeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}

初始化完成阶段

通过下面这个接口来实现
在这里插入图片描述
preInstantiateSingletons在这个方法里面被调用,他通常需要在ApplicationContext来进行使用,需要显式的调用。确保Bean已经被完全初始化。
在这里插入图片描述

Spring Bean销毁阶段

在这里插入图片描述
DisposableBeanAdapter#destroy()
销毁前:
DestructionAwareBeanPostProcessor

@Override
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
}
beanFactory.addBeanPostProcessor(new MyDestructionAwareBeanPostProcessor());
// 这个销毁是在容器中销毁 而不是在Java 中销毁
beanFactory.destoryBean("person", person);

Spring销毁阶段

有这样几种方式
在这里插入图片描述

Spirng Bean垃圾回收

在这里插入图片描述

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

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

相关文章

【C语言】字符串及其函数速览

字符串及其函数速览 字符串及其函数1. 字符串的输入输出1.1 gets()1.2 fgets()1.3 puts()1.4 fputs()输入输出函数案例 2. 字符串相关函数速览2.1 字符串赋值strset()strnset()strcpy()strncpy()strdup()下面的mem系列函数不仅能作用于字符&#xff0c;也能作用于其他类型memse…

【Java面试】三、Redis篇(下)

文章目录 1、抢券场景2、Redis分布式锁3、Redisson实现分布式锁4、Redisson实现的分布式锁是可重入锁5、Redisson实现分布式锁下的主从一致性6、面试 1、抢券场景 正常思路&#xff1a; 代码实现&#xff1a; 比如优惠券数量为1。正常情况下&#xff1a;用户A的请求过来&a…

DeepRec Extension 打造稳定高效的分布式训练

DeepRec Extension 即 DeepRec 扩展&#xff0c;在 DeepRec 训练推理框架之上&#xff0c;围绕大规模稀疏模型分布式训练&#xff0c;我们从训练任务的视角提出了自动弹性训练&#xff0c;分布式容错等功能&#xff0c;进一步提升稀疏模型训练的整体效率&#xff0c;助力 DeepR…

开源RAG,本地mac启动 dify源码服务

一、Dify文档 参考官方文档来操作&#xff0c;基本没太大的问题。一些细节&#xff0c;我在本篇文章中补充了出来。 这篇文章主要讲以源码的方式启动后端服务&#xff0c;前端服务使用容器启动。 dify 文档地址 欢迎使用 Dify | 中文 | Dify Dify 本地源码部署文档&#xff…

如何解读伊朗发布的直升机事故调查报告?一般事故调查报告应怎么写?

如何解读伊朗发布的直升机事故调查报告&#xff1f;一般事故调查报告应怎么写&#xff1f; 据央视新闻客户端消息&#xff1a;当地时间5月23日&#xff0c;伊朗武装部队总参谋部发布首份已故总统莱希及其随行人员乘坐的直升机事故调查报告。以下是#李秘书讲写作#对报告内容的解…

C语言面向对象编程,linux同时控制TOF摄像头和RGB摄像头

linux应用层同时控制TOF和RGB摄像头&#xff0c;为了方便操作&#xff0c;统一接口&#xff0c;这里将TOF和RGB摄像头看成两个对象&#xff0c;对它们分别实现&#xff0c;初始化&#xff0c;去初始化&#xff0c;读取视频流&#xff0c;停止视频流&#xff0c;启动视频流&…

YOLOv8 | 卷积模块 | 即插即用的可变核卷积AKConv【附代码+小白可上手】

💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 在目标检测领域内,尽管YOLO系列的算法傲视群雄,但在某些方面仍然存在改进的空间。在YOLOv8提取特征的时候,卷积的核是固定的K*K大小,导致参数数量随着大小的增加呈平方级增长。显然,不同数据集和目标的形状…

基于微信的家庭理财管理小程序的设计与实现(论文+源码)_kaic

摘 要 随着中国经济的飞速发展&#xff0c;家庭收入不断增高&#xff0c;人们的消费除了简单的维持日常生活之外&#xff0c;还有其他的消费方式&#xff0c;比如旅游、电商购物等&#xff0c;层出不穷的消费方式带给人快乐的同时&#xff0c;也常常让一些人逐渐无法把握住自…

【LeetCode】每日一题 2024_5_24 找出最具竞争力的子序列(栈,模拟,贪心)

文章目录 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01;题目&#xff1a;找出最具竞争力的子序列题目描述代码与解题思路 每天进步一点点 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 题目&#xff1a;找出最具竞争力的子序列 题目链接&a…

建材行业工程设计资质人员不足对资质有哪些影响

资质申请与审批&#xff1a;在申请工程设计资质时&#xff0c;人员的数量和专业配置是考核的重要指标之一。如果企业人员不足&#xff0c;尤其是缺乏关键岗位的专业技术人员&#xff0c;将直接影响资质的申请和审批。建设部门在核查企业主要人员信息时&#xff0c;如果发现人员…

24年前端面试 高频经典(答案版)

目录 1、函数式编程是什么简单说下&#xff1f; 2、打包工具代码管理 git svn 了解多少&#xff1f; 3、什么是Webpack&#xff1f;它的主要功能是什么&#xff1f; 4、Webpack的核心概念是什么&#xff1f; 5、如何获取到父节点dom 祖父节点呢&#xff1f; 6、登录流…

广义线性chirplet变换【附MATLAB代码】

文章来源&#xff1a;微信公众号&#xff1a;EW Frontier 摘要 时频分析方法是一种刻画信号时变特征的有效工具&#xff0c;在相当长的一段时间内受到了广泛的关注。随着TF算法的发展&#xff0c;许多先进的方法被提出&#xff0c;可以提供更精确的TF结果。但是&#xff0c;不…

【LabVIEW FPGA入门】使用事件发生函数同步FPGA循环

1.使用事件发生函数 使用 Occurrences 函数来控制单独的同步活动。特别是&#xff0c;当您希望程序框图的一部分等待程序框图的另一部分完成任务而不强制 LabVIEW 进行轮询时&#xff0c;请使用这些函数。 您可以使用全局变量执行类似于occurrences函数的功能&#xff0c;通过一…

Nginx 是一款高性能的开源 Web 服务器软件

文章推荐 1 作为程序员&#xff0c;开发用过最好用的AI工具有哪些&#xff1f; 2 Github Copilot正版的激活成功&#xff0c;终于可以chat了 3 idea,pycharm等的ai assistant已成功激活 4 新手如何拿捏 Github Copilot AI助手&#xff0c;帮助你提高写代码效率 5 Jetbrains的a…

SQL——DML对表中数据的操作

# 创建数据库 create database if not exists db_BigData default character set gb2312 default collate gb2312_chinese_ci; # 创建表 create table if not exists db_BigData.stu (id int auto_increment primary key comment 主键ID,name var…

navicat15设置字类型为decimal的字段默认值失败

可能是由于我使用的破解版的原因,使用sql可以设置成功,但是navicat可视化工具就不行, sql如下: alter table <表名> alter column <字段名> set default <默认值> ;

Windows内核--DMA

DMA工作期间CPU可以访问内存吗? DMA工作期间&#xff0c;占用内存访问总线&#xff0c;和CPU访问内存总线是冲突的。DMA并不是完全和CPU工作并行&#xff0c;如果CPU只是在对内部寄存器操作&#xff0c;没有访问内存&#xff0c;CPU可以和DMA同时工作。一旦CPU也需要访问内存&…

详解CSS(二)

目录 1.背景属性 1.1背景颜色 1.2背景图片 1.3背景平铺 1.4背景位置 1.5背景尺寸 2.圆角矩形 3.元素的显示模式 3.1行内元素/内联元素&#xff08;Inline element&#xff09; 3.2块级元素&#xff08;Block-level element&#xff09; 3.3行内块元素&#xff08;In…

配置 tmux 状态栏

如果你希望 script_status.sh 脚本用于检测是否能正常上网,并将结果显示在 tmux 状态栏中,可以编写一个脚本来执行此操作。下面是如何实现这一功能的详细步骤: 编写 script_status.sh 脚本 首先,创建或编辑 script_status.sh 脚本,使其能够检测互联网连接状态。可以通过…

【leetcode面试经典150题】-80. 删除有序数组中的重复项 II

【leetcode面试经典150题】-80. 删除有序数组中的重复项 II 1 题目介绍2 个人解题思路2.1 代码2.2 思路 3 官方题解 1 题目介绍 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超过两次的元素只出现两次 &#xff0c;返回删除后数组…