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

@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垃圾回收

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vscode插件-06 Python

文章目录 Python(一般安装这一个就行)Pylance(跟随Python自动安装)Python Debugger(跟随Python自动安装)LiveCode for pythonSort linesPython Extension Pack(一般不安装)python snippets Python(一般安装这一个就行) 这个扩展是由微软官方提供的&#xff0c;支持但不仅限于以…

手撕C语言题典——轮转数组

目录 前言 一&#xff0c;思路 1&#xff09;暴力求解 O(N^2) 2&#xff09;三段逆置 二&#xff0c;代码实现 前言 随着C语言的深入&#xff0c;我们准备转向C方面学习&#xff0c;学习C之前我们需要搞懂时间复杂度&#xff0c;这个蛮重要的&#xff0c;我们将通过几个题…

RK3568笔记二十五:RetinaFace人脸检测训练部署

若该文为原创文章&#xff0c;转载请注明原文出处。 一、介绍 Retinaface是来自insightFace的又一力作&#xff0c;基于one-stage的人脸检测网络。RetinaFace是在RetinaNet基础上引申出来的人脸检测框架&#xff0c;所以大致结构和RetinaNet非常像。 官方提供两种主干特征提取网…

DVWA代码审计--文件上传

NO.1 Low 首先来看下代码 <?php if( isset( $_POST[ Upload ] ) ) { // Where are we going to be writing to? $target_path DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/"; $target_path . basename( $_FILES[ uploaded ][ name ] ); // Can we move the f…

u盘里文件损坏无法打开怎么恢复?五种方法恢复数据全解析

有时可能会遇到&#xff1a;插入U盘后&#xff0c;发现里面的文件损坏无法打开&#xff0c;有多种方法可以尝试来恢复损坏的文件。本文将介绍常见的方法解决U盘文件损坏无法打开的问题。 1. 使用文件修复工具 许多文件修复工具可以修复损坏文件。这些工具能够检测并修复文件中…

网关路由SpringCloudGateway、nacos配置管理(热更新、动态路由)

文章目录 前言一、网关路由二、SpringCloudGateway1. 路由过滤2. 网关登录校验2.1 鉴权2.2 网关过滤器2.3 登录校验2.3.1 JWT2.3.2 登录校验过滤器 3. 微服务从网关获取用户4. 微服务之间用户信息传递 三、nacos配置管理问题引入3.1 配置共享3.1.1 在Nacos中添加共享配置3.1.2 …

蓝桥杯物联网竞赛_STM32L071KBU6_关于sizo of函数产生的BUG

首先现象是我在用LORA发送信息的时候&#xff0c;左边显示长度是8而右边接收到的数据长度却是4 我以为是OLED显示屏坏了&#xff0c;又或者是我想搞创新用了const char* 类型强制转换数据的原因&#xff0c;结果发现都不是 void Function_SendMsg( unsigned char* data){unsi…

【Unity2D 2022:Cinemachine】相机跟随与地图边界

一、导入Cinemachine工具包 1. 点击Window-Package Manager&#xff0c;进入包管理界面 2. 点击All&#xff0c;找到Cinemachine工具包&#xff0c;点击Install 二、相机跟随角色 1. 选中Main Camera&#xff0c;点击Component-Cinemachine-CinemachineBrain&#xff0c;新建…

面了一个程序员,因为6休1拒绝了我

人一辈子赖以生存下去的主要就考虑三件事&#xff0c;职业&#xff0c;事业&#xff0c;副业&#xff0c;有其1-2都是很不错的。如果还没到40岁&#xff0c;那不妨提前想下自己可能遇到的一些情况&#xff0c;提前做一些准备&#xff0c;未雨绸缪些。 今年整体就业大环境也一般…

05 JavaSE-- 异常、IOStream、多线程、反射、Annotation、泛型、序列化

Exception 异常 异常也是对象&#xff0c;也有自己的体系&#xff0c;在这个体系中&#xff0c;所有异常对象的根类是 throwable 接口。异常和 error 错误是不同的概念。 错误是严重的 JVM 系统问题&#xff0c;一般不期待程序员去捕获、处理这些错误&#xff0c;同时&#xf…

55. UE5 RPG 处理当前功能在多人模式中的问题

在UE里面&#xff0c;我们运行项目可以设置多种网络模式&#xff0c;主要是分为三种&#xff1a; 运行Standalone 就是单人模式&#xff0c;没有网络交互以监听服务器运行&#xff0c;在界面里运行的游戏会作为服务器使用以客户端运行&#xff0c;UE会单独运行一个线程作为服务…

面向对象-----继承

前面向大家介绍了面向对象中的封装性&#xff0c;今天再来向大家介绍面向对象的继承和多态的两大特性。 1.继承 1.1 为什么需要继承&#xff1f; 在java语言中&#xff0c;我们用类来描述世间万物&#xff0c;虽然万物非常复杂&#xff0c;但总有一些共同点&#xff0c;如果…

深入Django项目实战与最佳实践

title: 深入Django项目实战与最佳实践 date: 2024/5/19 21:41:38 updated: 2024/5/19 21:41:38 categories: 后端开发 tags: Django 基础项目实战最佳实践数据库配置静态文件部署高级特性 第一章&#xff1a;Django项目架构与设计原则 Django框架概述 Django是一个高级的P…

linux的用户管理

新建用户&#xff1a;1.useradd 2.passwd 完成的操作&#xff1a; (1)/etc/passwd添加一行 (2)/etc/shadow添加一行 (3)/etc/group添加一行 (4)创建用户家目录 (5)创建用户邮件文件 例&#xff1a;创建用户jerry&#xff0c;要求: uid:777&am…

文心一言指令解析

1、介绍 文心一言是一款灵感启发类的产品&#xff0c;它以简洁而深刻的文字表达来激发读者的思考和感悟。该产品通过每天提供一句精选的短语&#xff0c;让用户在繁忙的生活中停下脚步&#xff0c;思考人生和内心的真实需求。 每一句文心一言都经过精心挑选&#xff0c;它们通…

苹果MacOS系统使用微软远程桌面连接Windows电脑桌面详细步骤

文章目录 前言1. 测试本地局域网内远程控制1.1 Windows打开远程桌面1.2 局域网远程控制windows 2. 测试Mac公网远程控制windows2.1 在windows电脑上安装cpolar2.2 Mac公网远程windows 3. 配置公网固定TCP地址 前言 日常工作生活中&#xff0c;有时候会涉及到不同设备不同操作系…

【SpringBoot】整合百度文字识别

流程图 一、前期准备 1.1 打开百度智能云官网找到管理中心创建应用 全选文字识别 1.2 保存好AppId、API Key和Secret Key 1.3 找到通用场景文字识别&#xff0c;立即使用 1.4 根据自己需要&#xff0c;选择要开通的项目 二、代码编写 以通用文字识别&#xff08;高精度版&am…

2024-5-4-从0到1手写配置中心Config之基于h2的config-server

添加依赖 新建的web工程中添加h2的依赖 添加h2的配置 设置数据源和密码设置初始化sql语句打开h2的控制台 初始化语句创建一个config表&#xff0c;保存服务配置信息。 完成CRUD接口 controller类 mapper接口 测试 在web控制台可以看到sql已经初始化完成&#xff0c;crud接口…

如何*永久*禁用edge打开PDF文件?

要永久禁用Microsoft Edge打开PDF文件&#xff0c;您可以按照以下步骤进行操作&#xff1a; 打开文件资源管理器并找到任意一个PDF文件。 右键单击该文件并选择“属性”。 在“属性”对话框中&#xff0c;单击“更改”按钮旁边的“打开方式”。 在“打开方式”对话框中&…

Leetcode - 398周赛

目录 一&#xff0c;3151. 特殊数组 I 二&#xff0c;3152. 特殊数组 II 三&#xff0c;3153. 所有数对中数位不同之和 四&#xff0c;3154. 到达第 K 级台阶的方案数 一&#xff0c;3151. 特殊数组 I 本题就是判断一个数组是否是奇偶相间的&#xff0c;如果是&#xff0c;…