【Spring源码解读四】IoC容器之AnnotationConfigApplication的refresh()刷新方法其三

news2024/11/29 12:40:20

finishBeanFactoryInitialization()

freezeConfiguration()

preInstantiateSingletons()

getBean()


        这一篇博文主要是记录refresh()方法中的finishBeanFactoryInitialization()方法。对于使用注解注入Bean的方式来说,这个方法是很重要的,它会初始化所有剩下的单实例Bean。

public AnnotationConfigApplicationContext(String... basePackages) {
	this();
	scan(basePackages);
	refresh();
}
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 刷新上下文
		// 在这里面主要做了三件事:初始化属性值、校验属性的合法性、创建容器保存早期应用事件
		prepareRefresh();

		// 在这个方法中主要是获取DefaultListableBeanFactory这个Bean工厂 后续都是在用
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 准备Bean工厂以便在此上下文中使用
		// 设置Bean工厂的类加载器等、注册可以解析的自动装配、添加后置处理器、注册默认的Bean环境
		prepareBeanFactory(beanFactory);

		try {
			// 允许在上下文子类中对Bean工厂进行后处理
			// 根据传来的是哪个子类就到其重写方法中创建和准备环境
			postProcessBeanFactory(beanFactory);

			// 调用在上下文中注册为bean的工厂处理器(重要)
			// 注解开发对包进行扫描得到Bean的定义
			invokeBeanFactoryPostProcessors(beanFactory);

			// 注册拦截bean创建的bean处理器 如果没有BeanProcessors 此步骤什么也不做
			registerBeanPostProcessors(beanFactory);

			// 初始化此上下文的消息源
			// 将messageSource这个Bean对象放到beanFactory中的singletonObjects中
			initMessageSource();

			// 初始化此上下文的事件多播
			// 将applicationEventMulticaster这个Bean对象放到beanFactory中的singletonObjects中
			initApplicationEventMulticaster();

			// 初始化特定上下文子类中的其他特殊bean
			onRefresh();

			// 检查侦听器bean并注册它们
			// 在所有Bean中查找Listener这个Bean对象并注册到消息广播中 没有的话什么也不做
			registerListeners();

			// 实例化所有剩余的(非惰性初始化)单例
            // 这一片博文主要就是记录这个方法
			finishBeanFactoryInitialization(beanFactory);

			// 最后一步:发布相应的事件
			finishRefresh();
		} catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources. 销毁已创建的singleton以避免挂起资源
			destroyBeans();

			// Reset 'active' flag. 重置“活动”标志
			cancelRefresh(ex);

			// Propagate exception to caller. 向调用方传播异常
			throw ex;
		} finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			// 重置Spring核心中的常见内省缓存,因为我们可能不再需要单例bean的元数据
			resetCommonCaches();
		}
	}
}

finishBeanFactoryInitialization()

        在看这个方法的源码前可以先看一下大概发生了什么事情。在registerListeners()方法与finishRefresh()方法都加个断点,看一下新增加了什么Bean。经过下面两张图可以发现,在BeanFactory中的sinletonObjects(bean一级缓存)中多了一个user对象。而这个bean就是在配置类中加的@Bean注解注册进来IoC容器的。所以说这一步就是来初始化那些剩余的没有处理的Bean。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	//  初始化此上下文的转换服务
	// 如果Bean工程包含conversionService并且符合这个类型 则获取这个转换服务
	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));
	}

	// 如果之前没有注册任何bean后处理器(如PropertyPlaceholderConfigurer bean),则注册默认的嵌入式值解析器:此时,主要用于注释属性值中的解析。
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// 尽早初始化LoadTimeWeaverWare bean,以便尽早注册其转换器,这是为了AspectJ的支持
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// 停止使用临时ClassLoader进行类型匹配。
	beanFactory.setTempClassLoader(null);

	// 缓存所有的BeanDefinition元信息,不希望未来发生变化
	beanFactory.freezeConfiguration();

	// 实例化所有剩余的(非惰性init)singleton。
	beanFactory.preInstantiateSingletons();
}

freezeConfiguration()

public void freezeConfiguration() {
	this.configurationFrozen = true;
	this.frozenBeanDefinitionNames = StringUtils.toStringArray(this.beanDefinitionNames);
}

preInstantiateSingletons()

        最主要看的就是finishBeanFactoryInitialization()方法的最后一行:也就是实例化剩余未处理的单例bean。这个方法进入到DefaultListableBeanFactory类中。这个类就是refresh()刷新方法的第二步获取到的Bean工厂。

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

	// 对副本进行迭代,以允许init方法注册新的bean定义
	// 虽然这可能不是常规工厂引导的一部分,但它在其他方面确实很好
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
	
	// 循环迭代所有的BeanDefinition
	for (String beanName : beanNames) {
		// 根据beanName 获取 BeanDefinition
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 如果此BeanDefinition未非抽象、单例、非懒加载就进入这个If中
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 判断这个beanName是否为FactoryBean(这里就多了个概念关于什么是FactoryBean)
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final FactoryBean<?> factory = (FactoryBean<?>) bean;
					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());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			} else {
				// 当不为FactoryBean 就在在这初始化Bean对象,并为其进行赋值操作
				getBean(beanName);
			}
		}
	}

	// 触发所有适用bean的初始化后回调
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			} else {
				smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

getBean()

        重要的就是非FactoryBean的情况下会将BeanName传入getBean()方法,然后就会进入AbstractBeanFactory类中。在doGetBean()方法中源码太多,就省略展示了,主要记录其主要的方法作用。

// 单例对象缓存:bean名称到bean实例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 单例工厂缓存:bean名称到ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 早期singleton对象的缓存:bean名称到bean实例
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 一组已注册的singleton,按注册顺序包含bean名称
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

    // 对Bean的名字进行转换
	final String beanName = transformedBeanName(name);
    Object bean;
    // 急切地检查单例缓存中是否有手动注册的单例 对应下面代码块的前两个方法
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        //...省略代码
    } else {
        //...省略代码
        if (!typeCheckOnly) {
		    // 标记该Bean为已经创建状态
			markBeanAsCreated(beanName);
		}
        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            // 检查这个BeanDefinition是否为抽象的 如果为抽象的则报异常
            checkMergedBeanDefinition(mbd, beanName, args);
            // 判断此BeanDefinition是否为单例的
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
	                    // 创建单例Bean
	                    return createBean(beanName, mbd, args);
                    } catch (BeansException ex) {
	                    // 从单例缓存中显式删除实例:它可能是在创建过程中急切地放在那里的,以允许循环引用解析。同时删除任何接收到对bean的临时引用的bean
	                    destroySingleton(beanName);
	                    throw ex;
                    }
                    // 检查Bean实例 如果是Bean则返回本身 如果是FactoryBean则返回FactoryBean
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                });
            } 
        } catch(BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }
}

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(beanName, "Bean name must not be null");
	synchronized (this.singletonObjects) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			// ...省略
			// 创建之前检查是否创建过(从isCreationCheckExclusions与singletonsCurrentlyInCreation中检查)
			beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<>();
			}
			try {
				// TODO 得到单例的Bean实例对象
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			} catch (IllegalStateException ex) {
				// ...省略
			} catch (BeanCreationException ex) {
				// ...省略
			} finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				afterSingletonCreation(beanName);
			}
			// 如果是一个新的Bean对象 把Bean放到Map中 这个方法在下面
			if (newSingleton) {
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

protected void addSingleton(String beanName, Object singletonObject) {
	synchronized (this.singletonObjects) {
		this.singletonObjects.put(beanName, singletonObject);
		this.singletonFactories.remove(beanName);
		this.earlySingletonObjects.remove(beanName);
		this.registeredSingletons.add(beanName);
	}
}

getSingleton()

        来到DefaultSingletonBeanRegistry类中执行。

@Nullable
public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// 从singletonObjects 这个Map中获取Bean对象 如果存在则不需要创建
	Object singletonObject = this.singletonObjects.get(beanName);
	// 如果缓存中不存在目标对象 则判断在singletonsCurrentlyInCreation中是否有这个BeanName
	// 可以看到这个判断用了双重检查锁(先判断是否为null再加锁再判断是否为null)
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			singletonObject = this.earlySingletonObjects.get(beanName);
			if (singletonObject == null && allowEarlyReference) {
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					singletonObject = singletonFactory.getObject();
					this.earlySingletonObjects.put(beanName, singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

createBean()

        这个方法在AbstractAutowireCapableBeanFacory类中。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	// 其它代码我都省略了
    // 创建Bean实例
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	// 首先根据BeanDefinition以及BeanName解析出Bean的Class对象
	Class<?> beanClass = resolveBeanClass(mbd, beanName);

	if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
		throw new BeanCreationException(mbd.getResourceDescription(), beanName,
				"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
	}

	// 如果存在Supplier回调 则调用obtainFromSupplier()进行初始化
	Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
	if (instanceSupplier != null) {
		return obtainFromSupplier(instanceSupplier, beanName);
	}

	// 如果工厂方法不为空 则使用工厂方法初始化策略
	if (mbd.getFactoryMethodName() != null) {
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// 重新创建同一个bean时的快捷方式
	boolean resolved = false;
	boolean autowireNecessary = false;
	if (args == null) {
		synchronized (mbd.constructorArgumentLock) {
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				resolved = true;
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	if (resolved) {
		if (autowireNecessary) {
			return autowireConstructor(beanName, mbd, null, null);
		} else {
			return instantiateBean(beanName, mbd);
		}
	}

	// 自动装配的条件构造
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// 默认构造的首选构造函数
	ctors = mbd.getPreferredConstructors();
	if (ctors != null) {
		return autowireConstructor(beanName, mbd, ctors, null);
	}

	// 无需特殊处理:只需使用无参数构造函数。
	return instantiateBean(beanName, mbd);
}

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

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

相关文章

使用Unity开发一个独立的区块链

Arouse Blockchain [Unity独立区块链] 这是一个学习性质的项目&#xff0c;使用了Unity进行独立区块链游戏的开发。使用此项目&#xff0c;将默认你有一定的Unity基础&#xff0c;如果你是Unity小白&#xff0c;可以先学习Unity&#xff0c;B站有大量的教材。 内容列表 项目的…

武职301-day01

文章目录 实现永和小票页面效果图问题分析开发分析开发步骤order.html页面 问题&#xff1a;HTML代码和CSS样式代码混杂在一起网页中使用样式style修饰常用2种方式自定义样式表base.css 作业 实现永和小票页面 效果图 问题分析 把一个大的开发任务&#xff0c;先进行任务分析…

web前端-ES6语法学习

Vue3.0的学习 ES6的模块化语法ES6 模块化规范的概述ES6 模块化的体验默认导出与默认导入按需导出 和 按需导入直接导入并执行模块中的代码 Promiseasync/awaitEventLoop宏任务和微任务 ES6的模块化语法 ES6中文教程网&#xff1a;https://www.w3cschool.cn/escript6/ ES6 模块…

Makerbase SimpleFOC ESP32 例程8 电机旋钮控制测试

Makerbase SimpleFOC ESP32 例程8 电机旋钮控制测试 第一部分 硬件介绍 1.1 硬件清单 序号品名数量1ESP32 FOC V1.0 主板12YT2804电机2312V电源适配器14USB 线156pin杜邦线2 注意&#xff1a;YT2804是改装的云台无刷电机,带有AS5600编码器&#xff0c;可实现360连续运转。 …

基于java springboot+mybatis OA办公自动化系统设计和实现

基于java springbootmybatis OA办公自动化系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系方…

利用fiddler测试APP及高级应用

我们经常需要用到Fiddler做代理服务器对Web、APP应用进行抓包&#xff0c;以便我们对接口功能进行测试调试&#xff0c;定位问题等。这篇将讲述怎么通过Fiddler对APP进行抓包&#xff0c;以及简单介绍一些高级应用场景。 首先&#xff0c;附上Fiddler使用的环境配置清单&#…

社会心理学(2) 社会心理学的研究方法

下面我们来说 社会心理学的研究方法 那么 首先 要说方法论 有些心理学者 他不分方法和方法论 但是 我们还是将他分开 一般的理解 方法论和方法 具体做法不同 方法论 我们定义为 研究心理学的最高或最原则 指导思想 有了这个指导思想 我们就可以更好的决定 对研究的问题 用…

扫码点餐小程序是什么?为什么现在餐厅都在用扫码点餐?

开餐厅的你有没有遇见一种有这样的情况 爆单的时间点就那么一小段&#xff0c;但是人一多呢&#xff0c;出品和点单很容易混乱&#xff0c;从而流失很多客户。 针对与这种情况&#xff0c;便有了扫码点餐。 小程序是一种为餐饮商家提供的解决方案&#xff0c;它可以帮助商家…

k8s集群删除master节点

1.在另外的master节点执行以下命令 kubectl get node #查看需要删除的节点名称 kubectl delete node k8s-master01 #删除名为k8s-master01的节点 2.在k8s-master01清空集群配置信息 kubeadm reset --cri-socketunix:///var/run/cri-dockerd.sock #因为我使用的是1.…

Redis - 数据结构类型及使用场景详解

一. 简介 Redis 是由 Salvatore Sanfilippo 编写的一个key-value存储系统&#xff0c;是跨平台的非关系型数据库。Redis是一个开源的&#xff0c;使用C语言编写的&#xff0c;遵守BSD协议&#xff0c;支持网络&#xff0c;可基于内存&#xff0c;分布式&#xff0c;可选持久性的…

基于Java健身房管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

搭建Jmeter分布式压测与监控,轻松实践

对于运维工程师来说&#xff0c;需要对自己维护的服务器性能瓶颈了如指掌&#xff0c;比如我当前的架构每秒并发是多少&#xff0c;我服务器最大能接受的并发是多少&#xff0c;是什么导致我的性能有问题&#xff1b;如果当前架构快达到性能瓶颈了&#xff0c;是横向扩容性能提…

很详细的Django开发入门详解(图文并茂)

1.Django概述 Django是一个开放源代码的Web应用框架&#xff0c;由Python写成。采用了MTV的框架模式&#xff0c;即模型M&#xff0c;视图V和模版T。 Django 框架的核心组件有&#xff1a; 用于创建模型的对象关系映射&#xff1b;为最终用户设计较好的管理界面&#xff1b;…

一些可以参考的文档集合12

之前的文章集合: 一些可以参考文章集合1_xuejianxinokok的博客-CSDN博客 一些可以参考文章集合2_xuejianxinokok的博客-CSDN博客 一些可以参考的文档集合3_xuejianxinokok的博客-CSDN博客 一些可以参考的文档集合4_xuejianxinokok的博客-CSDN博客 一些可以参考的文档集合5_…

C语言设计实现十六进制与十进制数之间的相互转换

一、十六进制数转为十进制数 1.设计一个C语言代码实现十六进制数例如0xFEFF转为十进制 以下是一个C语言代码示例&#xff0c;用于将十六进制数转换为十进制&#xff1a; #include <stdio.h> #include <stdlib.h>int main() {char hexNum[10]; // 存储输入的十六…

操作系统:详解物理内存与虚拟内存,用户空间与内核态空间

目录 0、基础知识&#xff1a;磁盘与物理内存 1、 通过虚拟地址访问物理内存 1.1 虚拟内存&#xff1a; 1.2 虚拟内存的优势&#xff1a; 1.3 举例说明&#xff1a; 2、用户空间与内核态空间 2.1 为什么进程的寻址空间要划分为用户空间与内核态空间两部分&#xff1f;&am…

装饰者模式(十一)

请相信自己&#xff0c;请再次相信自己&#xff0c;请一定要相信自己 上一章简单介绍了桥接模式(十), 如果没有看过, 请观看上一章 一. 装饰者模式 引用 菜鸟教程里面的装饰者模式介绍: https://www.runoob.com/design-pattern/decorator-pattern.html 装饰器模式&#xff0…

什么是开源工作流平台?

在办公职场中&#xff0c;有没有一款软件是实现提质增效的平台&#xff1f;如果让办公实现流程化管理&#xff0c;引用什么平台产品较为合适&#xff1f;低代码开发平台是近些年较为流行的办公软件平台&#xff0c;可以有效管理数据资源&#xff0c;制作表格可视化操作更简便&a…

Qt Quick系列(6)—多风格UI页面

&#x1f680;作者&#xff1a;CAccept &#x1f382;专栏&#xff1a;Qt Quick 文章目录 前言桌面版本的UI界面代码示例相关知识点 移动版风格的UI界面代码示例 嵌套页面代码示例相关知识点 并排页面代码示例相关知识点 前言 Qt Quick控件用于创建由标准化组件&#xff08;…

OpenCV迭代去畸变undistortPoints 与vins的迭代不同 vins前端与imu预积分

OpenCV去畸变undistortPoints原理解析 不动点迭代法—单变量非线性方程近似根matlab求解 淦VINS-MONO源码 03–openCV与VINS中去畸变方法的不同 这里用的方法和openCV不同&#xff0c;假设现在求A点的去畸变坐标&#xff0c;那么我们将A的坐标直接代入畸变模型中&#xff0c;求…