SpringBean-生命周期

news2024/12/24 9:10:31

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

@Override
	public 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_INFRASTRUCTURE
				if (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 phase
				this.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 {

    @Bean
    public 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 {
        @Override
        public 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.coloradmin.cn/o/1684853.html

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

相关文章

从零开始搭建SpringCloud Alibaba微服务架构

Spring Cloud Alibaba是Spring Cloud的一个拓展项目&#xff0c;它用于构建基于阿里巴巴的微服务应用。它提供了多个阿里巴巴的开源组件&#xff0c;如Nacos、Sentinel、Dubbo等&#xff0c;用于解决微服务架构中的服务注册、配置管理、流量控制等问题。 Spring Cloud Alibaba…

老题重测,国产AI大模型从“智障”走向“智能”?

2023年8月&#xff0c;拿我家小孩的一道小学数学题来测试了一批知名的国产大模型&#xff0c;结果很失望&#xff0c;没有一个能答对。最近正好看到OpenAI GPT-4o发布的新闻&#xff0c;于是跑去重测了一遍&#xff0c;结果很惊喜&#xff0c;绝大部分国产AI大模型都给出清晰、…

MySQL密码忘记之通过Navicat保存的加密密码来解码过程

MySQL密码忘记之通过Navicat保存的加密密码来解码过程 一、前言 许久不用数据库MySQL&#xff0c;因此密码忘记&#xff0c;但是在Navicat上保存了MySQL的密码&#xff0c;然而Navicat上保存的密码是加密的&#xff0c;无法直接复制来使用&#xff0c;因此需要对Navicat上保存…

如何停止 iPad 和 iPhone 之间共享短信,独立接收和发送消息

概括 在当今高度互联的数字世界中&#xff0c;Apple 设备之间的无缝连接性提供了极大的便利&#xff0c;尤其是在消息同步方面。iPhone 和 iPad 用户通常可以享受到设备间短信的自动同步功能&#xff0c;这意味着无论是在哪个设备上&#xff0c;用户都可以接收和回复消息。然而…

英伟达发布亮眼财报,大超预期!

KlipC报道&#xff1a;5月22日美股收盘后&#xff0c;英伟达公布第一财季财报。实现了260亿美元营收&#xff0c;远超分析师预测的246.5亿美元&#xff0c;同比增长262%。Q1净利润148.1亿美元&#xff0c;同比增长628%。此外&#xff0c;Q1毛利率也继续上升&#xff0c;达到了7…

VMware ESXi 7.0 U3q 发布 - 领先的裸机 Hypervisor

VMware ESXi 7.0 U3q 发布 - 领先的裸机 Hypervisor VMware ESXi 7.0 Update 3 Standard & All Custom Image for ESXi 7.0U3 Install CD 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-7-u3/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出…

【HCIP学习】RSTP和MSTP

一、RSTP&#xff08;Rapid Spanning Tree Protocol&#xff0c;快速生成树&#xff09; 1、背景&#xff1a;RSTP从STP发展而来&#xff0c;具备STP的所有功能&#xff0c;可以兼容stp运行 2、RSTP与STP不同点 &#xff08;1&#xff09;减少端口状态 STP:disabled\blockin…

Diffusion Policy:基于扩散模型的机器人动作生成策略

项目地址&#xff1a; Diffusion Policy (columbia.edu) 一、摘要 本文介绍了 "扩散策略"&#xff0c;这是一种生成机器人行为的新方法&#xff0c;它将机器人的视觉运动策略&#xff08;visuomotor policy&#xff09;表示为条件去噪扩散过程&#xff08;conditi…

P1【知识点】【数据结构】【链表LinkedList】C++版

链表是一种逻辑上连续&#xff0c;内存上分散的线性表数据结构&#xff0c;是用一组任意的空间&#xff08;可以连续&#xff0c;也可以不连续&#xff09;来存放数据元素。每个数据元素成为一个”结点“&#xff0c;每个结点由数据域和指针域组成。 访问元素&#xff08;Acce…

RK3588 Android13 TvSetting 中增加字体大小调整菜单

前言 电视产品,客户要求在设置中设备偏好设置子菜单里的显示和声音二级菜单里增加字体大小菜单功能, 其实里面本来有个文字缩放菜单,但不满足客户需求,那就新加一个也不是什么难事,开整。 效果图 TvSetting 部分修改文件清单 packages/apps/TvSettings/Settings/res/va…

解锁 user-agent(UA)识别 Api 接口的无限潜力

近年来&#xff0c;随着移动设备的普及和互联网的迅猛发展&#xff0c;用户使用不同的操作系统、浏览器以及硬件设备来访问网页的情况越来越多样化。为了更好地了解用户的访问环境和提供更好的用户体验&#xff0c;我们需要通过用户的访问UA&#xff08;User-Agent&#xff09;…

指针,指针变量,引用,取地址符,malloce()函数使用,C中“—>” 和“ . ” 作用与区别

目录 一&#xff1a;指针,指针变量&#xff0c;引用&#xff0c;取地址符&#xff1a; 前提 &#xff1a; 1.“ * ” 的两种用途 2." & “的两种用途 2.1&#xff1a;引用 2.2&#xff1a;取地址 补充&#xff1a; 二 : malloc(),动态申请地址空间 1.原型定义…

IEEE Transactions on Neural Networks and Learning Systems神经网络和学习系统TNNLS论文投稿须知

一、TNNLS介绍 IEEE Transactions on Neural Networks and Learning Systems作为控制领域的TOP期刊&#xff0c;2024年5月影响因子为10.4&#xff0c;虽然有些下降&#xff0c;之前五年平均影响因子为11.2&#xff0c;但依然是该领域王牌期刊&#xff0c;接收关于神经网络和相…

Python踩坑系列之使用redis报错:module ‘redis‘ has no attribute ‘Redis‘问题

一步一步往后看哦&#xff01;&#xff01;&#xff01; 纳尼&#xff0c;大伙看看这是什么情况&#xff0c;都是这么写的呢&#xff0c;为啥我这就报错了0.0 出现问题不可怕&#xff0c;解决它就完事了。 方法一、安装redis重新运行程序 pip install redis 无果&#xff0…

【kubernetes】探索k8s集群中kubectl的陈述式资源管理

目录 一、k8s集群资源管理方式分类 1.1陈述式资源管理方式&#xff1a;增删查比较方便&#xff0c;但是改非常不方便 1.2声明式资源管理方式&#xff1a;yaml文件管理 二、陈述式资源管理方法 2.1查看版本信息 2.2查看资源对象简写 2.3配置kubectl自动补全 2.4node节点…

10 - 核心对象 Switch / case

简介 在Kettle&#xff08;也称为Pentaho Data Integration&#xff0c;PDI&#xff09;中&#xff0c;Switch/Case 是一个关键的组件&#xff0c;用于根据特定条件将数据流分支到不同的路径。Switch组件评估输入数据中的某个字段&#xff0c;并将数据标记后传递给相应的Case组…

一款数字化管理平台源码:云MES系统(附架构图、流程)技术架构:springboot + vue-element-plus-admin

制造生产企业打造数字化生产管控的系统&#xff0c;从原材料、生产报工、生产过程、质检、设备、仓库等整个业务流程的管理和控制&#xff0c;合理安排生产计划、实时监控生产、优化生产工艺、降低不良产出和运营成本&#xff1b; 技术架构&#xff1a;springboot vue-elemen…

LLaMa系列模型详解(原理介绍、代码解读):LLaMA 3

LLaMA 3 2024年4月18日&#xff0c;Meta 重磅推出了Meta Llama 3&#xff0c;Llama 3是Meta最先进开源大型语言模型的下一代&#xff0c;包括具有80亿和700亿参数的预训练和指令微调的语言模型&#xff0c;能够支持广泛的应用场景。这一代Llama在一系列行业标准基准测试中展示…

UI问题 --- CardView和其它的控件在同一布局中时,始终覆盖其它控件

原本代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"40dp"android:layout_height"wrap_content"andr…

【Vue3】env环境变量的配置和使用(区分cli和vite)

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、env文件二、vue3cli加载env1..env配置2..dev配置&#xff08;其他环境参考&#xff09;3.package.json文件4.使用 三、vue3vite加载e…