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

文章目录

  • 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,所以没有直接实例化,而是在调用的时候进行的实例化。
实现流程
在这里插入图片描述

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

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

相关文章

8990890

作者主页&#xff1a;作者主页 数据结构专栏&#xff1a;数据结构 创作时间 &#xff1a;2024年5月18日

Mac OS 用户开启 8080 端口

开启端口 sudo vim /etc/pf.conf # 开放对应端口 pass out proto tcp from any to any port 8080 # 刷新配置文件 sudo pfctl -f /etc/pf.conf sudo pfctl -e获取本机ip地址 ifconfig en0 | grep inet | grep -v inet6 | awk {print $2}访问指定端口

JAVA环境的安装

一、JAVA环境的安装 像Java和一些其他的高级语言计算机直接识别不了&#xff0c;需要进行翻译&#xff0c;所以需要事先安装翻译工具 文件都在硬盘上&#xff0c;程序都在内存中 具体操作流程&#xff1a; 一、JDK的下载及安装 二、配置JAVA环境 1.打开环境变量 2.新建系…

Linux云计算架构师涨薪班就业服务有哪些?

学员一站式就业服务:一次学习&#xff0c;薪资翻倍 简历制作与指导 学员在培训期间&#xff0c;人才顾问会提供简历制作和指导服务&#xff0c;帮助学员制作出一份专业、有吸引力的简历。简历是求职者给招聘单位的第一印象&#xff0c;因此非常重要 模拟面试与技巧指导 为了让…

SpringBoot定时任务+Quartz 动态调度

1、分部解释 2、完整代码 3、SpringBoot定时任务Quartz 1、动态定时任务&#xff1a; 动态定时任务&#xff0c;即定时任务的动态调度&#xff0c;可根据需求自由的进行任务的生成、暂停、恢复、删除和更新操作。Quartz本身没有提供动态调度的功能,需要自己根据相关的API开发。…

Github 2024-06-06 Go开源项目日报 Top10

根据Github Trendings的统计,今日(2024-06-06统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Go项目10Ollama: 本地大型语言模型设置与运行 创建周期:248 天开发语言:Go协议类型:MIT LicenseStar数量:42421 个Fork数量:2724 次关注人…

小程序丨最大填表限制如何开启?

老师在新建填表时&#xff0c;希望设置最大数量限制&#xff0c;若填表达到限制&#xff0c;后续的学生将不能继续提交填表。 通过开启【表格最大限制】功能即可实现&#xff0c;下面就来教大家如何制作吧。 &#x1f50e;如何开启表格最大限制功能&#xff1f; 按照常规流程…

探索 LLM 预训练的挑战,GPU 集群架构实战

万卡 GPU 集群实战&#xff1a;探索 LLM 预训练的挑战 一、背景 在过往的文章中&#xff0c;我们详细阐述了LLM预训练的数据集、清洗流程、索引格式&#xff0c;以及微调、推理和RAG技术&#xff0c;并介绍了GPU及万卡集群的构建。然而&#xff0c;LLM预训练的具体细节尚待进一…

Web安全:Web体系架构存在的安全问题和解决方案

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

word2016版本中同时显示多个页面

为了方便查看word内容&#xff0c;我们会将多个页面同时显示。 对于2016版&#xff0c;操作方法如下&#xff1a; 视图 ---》多页

上海亚商投顾:沪指震荡下跌 两市成交不足7000亿元

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日震荡调整&#xff0c;创业板指冲高回落。车路云概念股持续活跃&#xff0c;万通智控、鸿泉物联、华体…

AI炒股:获取个股的历史成交价格并画出K线图

任务&#xff1a;获取贵州茅台的近几个月的价格数据&#xff0c;绘制k线图&#xff1b; 在deepseek中输入提示词&#xff1a; 你是一个Python编程专家&#xff0c;要完成一个编写Python脚本的任务&#xff0c;具体步骤如下&#xff1a; 用AKShare库获取股票贵州茅台&#xf…

超级详细Spring AI运用Ollama大模型

大模型工具Ollama 官网:https://ollama.com/ Ollama是一个用于部署和运行各种开源大模型的工具; 它能够帮助用户快速在本地运行各种大模型&#xff0c;极大地简化了大模型在本地运行的过程。用户通过执行几条命令就能在本地运行开源大模型&#xff0c;如Lama 2等; 综上&#x…

【毕业设计之微信小程序系列】基于微信小程序的餐厅点餐小程序的设计与实现

《基于微信小程序的餐厅点餐小程序的设计与实现》 项目效果图 目录大纲 摘要 1、选题及其意义 1.1、设计项目的名称 1.2、研究意义 2、需求分析 2.1、用户需求分析 2.2、功能需求分析 2.3、非功能需求分析 3、系统相关技术概述 3.1、餐饮平台开发相关技术 3.1.1、微信小程序 …

适用于 Windows 的 8 大数据恢复软件

数据恢复软件可帮助您恢复因意外删除或由于某些技术故障&#xff08;如硬盘损坏等&#xff09;而丢失的数据。这些工具可帮助您从硬盘驱动器 (HDD) 中高效地恢复丢失的数据&#xff0c;因为这些工具不支持从 SSD 恢复数据。重要的是要了解&#xff0c;您删除的数据不会被系统永…

NAT端口映射,实现外网访问内网服务器

目录 前言一、搭建网络拓扑1.1 配置server和pc1.1.1 配置server01.1.2 配置server11.1.3 配置pc0 1.2 配置客户路由器1.2.1 配置路由器IP1.2.2 配置静态路由 1.3 配置ISP路由器 二、配置端口映射2.1 在客户路由器配置端口映射2.2 测试公网计算机访问私网服务器2.2.1 PC0向serve…

一个简单的方式看看MySQL的锁

突然发现半个月没写了。最近事情太多了。 在日常工作的处理问题的过程中&#xff0c;我发现了一个简单的论证锁的问题&#xff0c;以前我讲的有点复杂&#xff0c;看来应该去改改之前的讲法了。 首先构造一个无主键无索引的表。并且初始化5条数据。 场景A&#xff1a; RR隔离…

珈和科技携手浙江省气候中心,打造农业气象数字化服务新标杆!

古谚有云&#xff1a;春耕夏种秋收冬藏&#xff0c;皆在天时。可天有不测风云&#xff0c;农有“旦夕祸福”。寒潮、干旱、洪涝等气象灾害频繁发生&#xff0c;给农业生产带来了巨大挑战。 气候变化直接影响着农业生产&#xff0c;数字化时代&#xff0c;如何依靠科技手段降低…

【UML用户指南】-08-对基本结构建模-图

目录 1、41视图 2、术语和概念 3、结构图 &#xff08;1&#xff09;类图&#xff08;class diagram&#xff09;&#xff1a; &#xff08;2&#xff09;构件图&#xff1a;&#xff08;component diagram&#xff09; &#xff08;3&#xff09;组合结构图&#xff1a;…