09-spring的bean创建流程(一)

news2024/10/6 16:25:15

文章目录

  • spring中bean的创建流程
    • finishBeanFactoryInitialization(beanFactory)
    • beanFactory.preInstantiateSingletons();
    • getMergedLocalBeanDefinition(beanName);流程
    • 实现FactoryBean接口,里面的对象实例化过程

spring中bean的创建流程

finishBeanFactoryInitialization(beanFactory)

在refresh方法中知道此方法就是初始化剩下的单实例

				// Instantiate all remaining (non-lazy-init) singletons.
				// 初始化剩下的单实例(非懒加载的)
				finishBeanFactoryInitialization(beanFactory);
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		// 为上下文初始化类型转换器
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		// 如果beanFactory之前没有注册嵌入值解析器,则注册默认的嵌入值解析器,主要用于注解属性值的解析
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		// 尽早初始化loadTimeWeaverAware bean,以便尽早注册它们的转换器
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		// 禁止使用临时类加载器进行类型匹配
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		// 冻结所有的bean定义,说明注册的bean定义将不被修改或任何进一步的处理
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		// 实例化剩下的单例对象
		beanFactory.preInstantiateSingletons();
	}

首先是初始化类型转换器,此转换器在spring mvc中较多,后续具体再看,这里的主要逻辑是获取名为conversionService类型为ConversionService.class的bean,使用此bean对对象做一个转换服务。
可以自定义实现这样的转换

public class Student {

    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
import org.springframework.core.convert.converter.Converter;

public class StudentConverter implements Converter<String,Student> {
    @Override
    public Student convert(String source) {
        System.out.println("-----");
        Student s  = new Student();
        String[] splits = source.split("_");
        s.setId(Integer.parseInt(splits[0]));
        s.setName(splits[1]);
        return s;
    }
}

beanFactory.preInstantiateSingletons();

此方法是实例化剩下的单例对象

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 将所有BeanDefinition的名字创建一个集合
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 触发所有非延迟加载单例bean的初始化,遍历集合的对象
		for (String beanName : beanNames) {
			// 合并父类BeanDefinition
 			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 条件判断,抽象,单例,非懒加载
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 判断是否实现了FactoryBean接口
				if (isFactoryBean(beanName)) {
					// 根据&+beanName来获取具体的对象
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					// 进行类型转换
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						// 判断这个FactoryBean是否希望立即初始化
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						//  如果希望急切的初始化,则通过beanName获取bean实例
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					// 如果beanName对应的bean不是FactoryBean,只是普通的bean,通过beanName获取bean实例
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// 遍历beanNames,触发所有SmartInitializingSingleton的后初始化回调
		for (String beanName : beanNames) {
			// 获取beanName对应的bean实例
			Object singletonInstance = getSingleton(beanName);
			// 判断singletonInstance是否实现了SmartInitializingSingleton接口
			if (singletonInstance instanceof SmartInitializingSingleton) {
				// 类型转换
				SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				// 触发SmartInitializingSingleton实现类的afterSingletonsInstantiated方法
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

getMergedLocalBeanDefinition(beanName);流程

此方法是合并父类BeanDefinition,这里面使用了递归处理
流程如下
在这里插入图片描述

实现FactoryBean接口,里面的对象实例化过程

if (isFactoryBean(beanName)) {
					// 根据&+beanName来获取具体的对象
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					// 进行类型转换
					if (bean instanceof FactoryBean) {
						FactoryBean<?> factory = (FactoryBean<?>) bean;
						// 判断这个FactoryBean是否希望立即初始化
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged(
									(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						//  如果希望急切的初始化,则通过beanName获取bean实例
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}

何为FactoryBean?他与BeanFactory有什么区别
先看FactoryBean的类的结构,此接口里面仅有getObject()、getObjectType()、isSingleton()这三个方法,使用这个类将实例注入到bean工厂中,不需要严格遵循BeanFactory里面bean的构建流程(初始化、实例化、aware接口、前置处理、后置处理),可以在FactoryBean中直接调用getObject()直接生成bean对象,并放入到factoryBeanObjectCache集合中,此集合是个Map。没有放到三级缓存中。后续如果需要则从factoryBeanObjectCache这个集合中获取。
特别:非单例情况下,实例始终不会往factoryBeanObjectCache中放,即非单例不会有缓存

如何实现FactoryBean

public class MyFactoryBean implements FactoryBean<User> {

    @Override
    public User getObject() throws Exception {
        return new User("zhangsan");
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

public class User {

    private String username;

    public User() {
    }

    public User(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                '}';
    }
}

当上面的逻辑处理完成时(这里粗略的看就是refresh方法完成),这时FactoryBean中已经有实现了FactoryBean的bean了,但是里面的对现象还没有放入到缓存中,如果这个类实现了SmartFactoryBean这个接口,并重写了isEagerInit方法,将其返回为true。那么在实例化FactoryBean这个对象的时候,里面的对象也会实例化并放入到factoryBeanObjectCache缓存中(非单例情况下,实例始终不会往factoryBeanObjectCache中放,即非单例不会有缓存)。这里没有实现SmartFactoryBean,只是实现了FactoryBean,所以没有直接实例化,而是在调用的时候进行的实例化。
实现流程
在这里插入图片描述

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

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

相关文章

14-ShardingSphere的分布式主键实现

1 ShardingSphere自动生成键 MySQL自增键、Oracle自增序列等。分片场景下问题就复杂了&#xff0c;不能依靠单实例上的自增键来实现不同数据节点之间的全局唯一主键&#xff0c;分布式主键的需求应运而生。ShardingSphere 作为一款优秀分库分表开源软件&#xff0c;同样提供分…

Ubuntu18.04安装pwntools报错解决方案

报错1&#xff1a;ModuleNotFoundError: No module named ‘setuptools_rust’ 报错信息显示ModuleNotFoundError: No module named setuptools_rust&#xff0c;如下图所示 解决方案&#xff1a;pip install setuptools_rust 报错2&#xff1a;pip版本低 解决方案&#xff…

【Test 49 】OSI 七层模型初识、网络传输的流程、IP地址和MAC地址! 面试高频考点!

文章目录 1. OSI七层模型2. TCP/IP五层(或四层)模型3. 网络传输基本流程 &#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#x1f427;&#…

MyBatis中的接口代理机制及其使用

1. MyBatis中的接口代理机制及其使用 文章目录 1. MyBatis中的接口代理机制及其使用2. 实操2.1 准备工作2.2 insert 增加操作2.3 delete 删除操作2.4 update 修改操作2.5 select 查询一条记录操作2.6 select 查询多条记录操作 3. 总结&#xff1a;4. 最后&#xff1a; MyBatis …

五、数据源池化技术实现

学这一节的时候重新梳理了DataSource、DriverManager、Driver、DriverProxy、Connection之间的关系&#xff0c;如下图 在整体流程中&#xff0c;这一块就是通过配置文件配置&#xff0c;在解析配置文件的时候就创建对应的数据源封装到Environment中&#xff0c;在执行sql的时…

使用Qt对word文档进行读写

目录 开发环境原理使用的QT库搭建开发环境准备word模板测试用例结果Gitee地址 开发环境 vs2022 Qt 5.9.1 msvc2017_x64&#xff0c;在文章最后提供了源码。 原理 Qt对于word文档的操作都是在书签位置进行插入文本、图片或表格的操作。 使用的QT库 除了基本的gui、core、…

3072. 将元素分配到两个数组中 II

题目 给你一个下标从 1 开始、长度为 n 的整数数组 nums 。 现定义函数 greaterCount &#xff0c;使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的元素数量。 你需要使用 n 次操作&#xff0c;将 nums 的所有元素分配到两个数组 arr1 和 arr2 中。在第一次操…

【调试笔记-20240604-Linux-为 OpenWrt LuCI 界面添加多语言支持】

调试笔记-系列文章目录 调试笔记-20240604-Linux-为 OpenWrt LuCI 界面添加多语言支持 文章目录 调试笔记-系列文章目录调试笔记-20240604-Linux-为 OpenWrt LuCI 界面添加多语言支持 前言一、调试环境操作系统&#xff1a;Ubuntu 22.04.4 LTS编译环境调试目标 二、调试步骤预…

vue-pdf 部分中文显示错误,第二次打开是空白,解决方法

首先鸣谢 1. https://blog.csdn.net/m0_71537867/article/details/131614868?spm1001.2014.3001.5506 2. https://blog.csdn.net/weixin_43763952/article/details/133769647 3. https://github.com/FranckFreiburger/vue-pdf/issues/229 4. https://blog.csdn.net/weixin_449…

Java中常用的单目运算符及用法详解

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

【Linux多线程】线程的终止、等待和分离

文章目录 线程终止正常退出return 退出pthread_exit函数终止线程 pthread_cancel强制终止线程进程终止 线程等待为什么需要等待线程&#xff1f;pthread_join函数 分离线程pthread_detach函数 线程终止 下面给出终止线程的三种方式&#xff1a; 正常退出&#xff1a; 线程执行…

【Flask-项目运行】解决用本机IP访问不到flask项目而用localhost可以访问到的问题

文章目录 一、问题描述二、解决办法 一、问题描述 使用 localhost 或 127.0.0.1 能访问到项目&#xff1a; 但是使用局域网 IP 访问不到&#xff1a; 二、解决办法 只需要在 app.py 中修改一行代码&#xff1a; run方法添加 host 参数指明全部 ip 可访问。

【Linux】(四)—— 文件权限管理

权限管理 这篇文章主要时对前篇文章中的用户和文件的权限操作做一些补充说明 用户权限&#xff1a; sudo&#xff1a;临时提升权限为root&#xff1b;sudo -s&#xff1a;永久提升权限为root。 ls -l显示的文件列表的第一列表示文件类型&#xff0c;第一个字母为-表示普通文…

wps:基本使用【笔记】

wps&#xff1a;基本使用【笔记】 前言版权推荐wps&#xff1a;基本使用如何去除复制文本的样式显示空格、换行、分节符快捷键设置字体添加章节添加奇数页分节符设置页边距设置页眉页脚设置页码 最后 前言 2024-6-5 23:10:12 以下内容源自《【笔记】》 仅供学习交流使用 版权…

vue3中的ref与reactive的区别

这里写自定义目录标题 1、两者的区别2、用法3、vue3中声明的数组/对象3.1 通过reactive 声明的Array/Object&#xff0c;需要重新分配一个全新的对象&#xff0c;会出错、或失去响应式效果 3.2 解决方案 4、cosnt 说明5、Proxy 与 defineProperty 1、两者的区别 ref&#xff1…

13- Redis 中的 压缩列表 数据结构

压缩列表的最大特点&#xff0c;就是它被设计成一种内存紧凑型的数据结构&#xff0c;占用 一块连续的内存空间&#xff0c;不仅可以利用 CPU 缓存&#xff0c;而且会针对不同长度的数据&#xff0c;进行相应编码&#xff0c;这种方法可以有效的节省内存开销。 但是&#xff0…

R语言探索与分析20-北京市气温预测分析

一、序言 近年来&#xff0c;人类大量燃烧煤炭、天然气等含碳燃料导致温室气 体过度排放&#xff0c;大量温室气体强烈吸收地面辐射中的红外线&#xff0c;造 成温室效应不断累积&#xff0c;使得地球温度上升&#xff0c;造成全球气候变暖。气象温度的预测一直以来都是天气预…

windows系统 flutter 开发环境配置

1、管理员运行powershell&#xff0c;安装&#xff1a;Chocolatey 工具&#xff0c;粘贴复制运行下列脚本: Chocolatey 官方安装文档 Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol [System.Net.ServicePointManage…

如何自动化地评估 AIGC 生图的质量?

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

秋招突击——算法打卡——6/5——提高{(状态机模型)股票买卖、(单调队列优化DP)最大子序列和}——新做:{考试的最大困扰度}

文章目录 提高(状态机模型)股票买卖IV思路分析实现代码参考代码 新作考试的最大困扰度个人实现参考思路 总结 提高 (状态机模型)股票买卖IV 上一次的思路总结&#xff0c;上次写的时候忘记总结了&#xff0c;现在重新画一下图 思路分析 这道题是一个经典的状态机模型&#…